• Tag Archives PowerShell
  • Send SMS through bibob with Powershell

    I thought I had posted this script more than a year ago, but apparently I have not. It is quite similar to the script, I posted recently sending SMS messages through unwire, this just allows bibob customers to send messages through bibobs online gateway.

    One thing to notice is that you are required to convert your password in an MD5 hash, before you send it. Here is a function to convert your plain passwords into an MD5 hash (Adapted from a script by Dennis Damen)

    [ps]
    Function New-MD5Hash {
    param(
    [Parameter(Position=0, Mandatory=$true)]
    [System.String]
    $inputString
    )
    $cryptoServiceProvider = [System.Security.Cryptography.MD5CryptoServiceProvider];
    $hashAlgorithm = new-object $cryptoServiceProvider
    $hashByteArray = $hashAlgorithm.ComputeHash($([Char[]]$inputString));
    foreach ($byte in $hashByteArray) { if ($byte -lt 16) {$result += “0{0:X}” -f $byte } else { $result += “{0:X}” -f $byte }}
    write-host $result
    }
    [/ps]
    Example of usage:

    Here is the bibob send sms script.
    [ps]
    <#
    .SYNOPSIS
    Send SMS through Bibob (Danish mobile phone company)

    .DESCRIPTION
    Send SMS Text messages through bibob SMS Gateway services

    .PARAMETER Content
    The text that the message should contain (Strings above 160 Chars will be split) [Mandatory]

    .PARAMETER Recipient
    The recipient phonenumber (8 digits) [Mandatory]

    .EXAMPLE
    PS C:\>Send-SMS -Content "Hello handsome" -Recipient 42424242

    .INPUTS
    System.String,System.Int32

    .OUTPUTS
    Sends SMS text message

    .NOTES

    .LINK
    about_functions_advanced

    .LINK
    about_comment_based_help

    #>

    function Send-SMS {
    [CmdletBinding()]
    param(
    [Parameter(Position=0, Mandatory=$true)]
    [System.String]
    $Content= "Hello Handsome",
    [Parameter(Position=1)]
    [System.Int32]
    $Recipient=42424242
    )
    begin {
    If ($Recipient -notmatch ‘^(\d{8})$’ )
    {Write-Host "Error in Phone Number"
    break
    }
    $Username = "42424242" # The same as your login to bibob.dk (You cannot spoof you sender number, so it is used as sender as well)
    $MD5Password = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

    }

    process {
    $objHTTP = New-Object -ComObject MSXML2.XMLHTTP
    $SoapServer = "https://www.bibob.dk/SmsSender.asmx"

    $XMLString = @"
    <?xml version="1.0" encoding="utf-8"?>
    <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
    <SendMessage xmlns="http://www.bibob.dk/">
    <cellphone>$Username</cellphone>
    <password>$MD5Password</password>
    <smsTo>
    <string>$recipient</string>
    </smsTo>
    <smscontents>$content</smscontents>
    <fromNumber>$username</fromNumber>
    </SendMessage>
    </soap:Body>
    </soap:Envelope>
    "@

    $objHTTP.open(‘POST’, $SoapServer, $False)

    $objHTTP.setRequestHeader(‘Man’, ‘POST’ + ‘ ‘ + $SoapServer + ‘ HTTP/1.1′)
    $objHTTP.setRequestHeader(‘Host’, ‘www.bibob.dk’)
    $objHTTP.setRequestHeader(‘Content-Type’, ‘text/xml; charset=utf-8′)
    $objHTTP.setRequestHeader(‘Content-Length’, $($XMLString.Length))
    $objHTTP.setRequestHeader(‘SOAPAction’, ‘http://www.bibob.dk/SendMessage’)

    $objHTTP.send($XMLString)
    }
    }

    [/ps]



  • Send SMS from Powershell through Unwire

    At work we have bought an SMS gateway service through the danish company Unwire, so after we the deal was signed we got the information on how to send email through their services, so in order to test I wrote a quick Powershell script to test it.

    Of course all company/Unwire specific data has been removed, since it relates to our company account.

    [ps]
    <#
    .SYNOPSIS
    Send SMS through Unwire GW Server

    .DESCRIPTION
    Send SMS Text messages through Unwire.com SMS Gateway services

    .PARAMETER Content
    The text that the message should contain (Strings above 160 Chars will be split) [Mandatory]

    .PARAMETER Recipient
    The recipient phonenumber (Either 8 or 10 digits) [Mandatory]

    .PARAMETER Sender
    The name/number that shows up on the recipients phone (Maximum 11 digits/chars)

    .EXAMPLE
    PS C:\>Send-SMS -Content "Hello handsome" -Recipient 42424242

    .EXAMPLE
    PS C:\> Send-SMS -Content "Hello handsome" -Recipient 42424242 -Sender "IT Helpdesk"

    .INPUTS
    System.String,System.Int64,System.String

    .OUTPUTS
    Sends SMS text message

    .NOTES

    .LINK
    about_functions_advanced

    .LINK
    about_comment_based_help

    #>

    function Send-SMS {
    [CmdletBinding()]
    param(
    [Parameter(Position=0, Mandatory=$true)]
    [System.String]
    $Content= "Hello There",
    [Parameter(Position=1, Mandatory=$true)]
    [System.Int64]
    $Recipient=42424242,
    [Parameter(Position=2, Mandatory=$false)]
    [System.String]
    $Sender="IT-Drift"
    )
    begin {

    If ( $Recipient -notmatch ‘^(\d{8}|\d{10})$’ )
    {Write-Host "Error in Phone Number"
    break
    }
    If ($Sender.Length -gt 11)
    {Write-Host "Sender name too long"
    break
    }
    [Void] [System.Reflection.Assembly]::LoadWithPartialName("System.Web")
    $objHTTP = New-Object -ComObject MSXML2.XMLHTTP

    $User = "xxxxx"
    $Password = "xxxxxx"
    $AppNr = "xxxxx"
    $smsc = "xxxxxx"
    $Price = "xxxxx"

    $Message = [System.Web.HttpUtility]::UrlEncode([System.Text.Encoding]::GetEncoding("ISO-8859-1").GetBytes("$Content"))
    $SenderName = [System.Web.HttpUtility]::UrlEncode([System.Text.Encoding]::GetEncoding("ISO-8859-1").GetBytes("$Sender"))

    [String] $unwireURL = "xxxxxxxx"
    [String] $UnwireServer = "xxxxxxxx"
    [String] $UnwireHost ="xxxxxxxxxx"

    }

    process {

    $PushString = @"
    user=$user&password=$password&to=$Recipient&text=$Message&smsc=$smsc&price=$Price&type=text&appnr=$AppNr&from=$SenderName
    "@

    $objHTTP.open(‘POST’, $UnwireServer, $False)

    $objHTTP.setRequestHeader(‘POST’, $unwireURL + ‘ HTTP/1.1′)
    $objHTTP.setRequestHeader(‘Host’, $UnwireHost)
    $objHTTP.setRequestHeader(‘User-Agent:’, ‘CP agent’)
    $objHTTP.setRequestHeader(‘Content-Type’, ‘application/x-www-form-urlencoded’)
    $objHTTP.setRequestHeader(‘Content-Length’, $($XMLString.Length))
    $objHTTP.send("$PushString")
    $objHTTP.status
    $objHTTP.statusText

    }
    }

    [/ps]



  • The (r)evolution of a script

    As those of you who a following my blog know, I have been fortunate enough to become a Microsoft MVP in Powershell, and because of that I have been allowed on the Powershell MVP mailing list, an let me tell, there are some amazing people out there, doing some amazing stuff. Some of the stuff floating around I don’t even have a clue what does ;)

    But people are also very helpful, and quick to jump in if someone has a problem or even if someone just posts a piece of code they find useful, people tend to jump in with suggestions/additions to make the script even better… Here is an example of a script that went from 14 lines of code to 334 in half a day.

    Tome Tanasovski wrote a quick and dirty script that connects to the MVP site, and cycles through all the categories, and returns how many MVP’s there are in each. He ended off by saying, that the results where not entirely correct, since some MVP has hidden the profile from the public list, meaning you would have to be logged in to see them.

    [ps]
    $web = New-Object System.Net.WebClient
    $regex = [regex]‘(?m)<a href=\"(\/communities\/mvp.aspx\?product=1&competency=(\S+))\"’
    $objects = @()
    $return = $web.DownloadString(‘http://mvp.support.microsoft.com/communities/mvp.aspx’)
    $regex.Matches($return) |% {
    $obj = New-Object psobject
    $obj |Add-Member NoteProperty -Name ‘Group’ -Value ($_.Groups[2].Value -replace ‘\+’,’ ‘)
    if ($web.DownloadString((‘http://mvp.support.microsoft.com’ + $_.Groups[1].Value)) -match ‘Results 1 \- \d+ of (\d+)’) {
    $obj |Add-Member NoteProperty -Name ‘Count’ -Value ([int]$matches[1])
    }
    $objects += $obj
    }

    $objects |sort Count -Descending |ogv
    [/ps]

    So I decided to write some simple IE automation that would log you you on to the Microsoft passport site, and count all the MVP’s, including those who do not have a public profile.

    [ps]
    $URI = "https://login.live.com/ppsecure/secure.srf?lc=1033&sf=1&id=259214&ru=https://mvp.support.microsoft.com/communities/mvp.aspx&tw=0&fs=0&kv=0&cb=wizid%3df4502d34-3b8f-4a04-b741-289e08aa1782%26lcid%3d1033%26returnurl%3dhttps%253a%252f%252fmvp.support.microsoft.com%252fcommunities%252fmvp.aspx%26brand%3dMicrosoft&cbcxt=&wp=MCMBI&wa=wsignin1.0&wreply=https://mvp.support.microsoft.com/communities/mvp.aspx&wlsu=1"
    $ie = new-object -com "InternetExplorer.Application"
    $ie.visible = $false
    $ie.navigate($URI)
    while ($ie.Busy -eq $true) { Start-Sleep -Milliseconds 1000; }
    $doc = $ie.Document
    $ie.Document.Body.InnerText.ToString()
    $user = $doc.getElementByID("Login")
    $user.value = "xxxxxxxxxx"
    $pass = $doc.getElementByID("Passwd")
    $pass.value = "xxxxxxxxxx"
    $Logon = $doc.getElementByID("SI")
    $Logon.click()
    while ($ie.LocationURL -ne "https://mvp.support.microsoft.com/communities/mvp.aspx") { Start-Sleep -Milliseconds 1000; }
    while ($ie.Busy -eq $true) { Start-Sleep -Milliseconds 1000; }
    #$ie.Document.Body.InnerHTML.ToString()

    $regex = [regex]‘(?m)<A href=\"(\/communities\/mvp.aspx\?product=1&amp;competency=(\S+))\"’
    $objects = @()

    $return = $ie.Document.Body.InnerHTML.ToString()

    $regex.Matches($return)|% {
    $obj = New-Object psobject
    $obj |Add-Member NoteProperty -Name ‘Group’ -Value ($_.Groups[2].Value -replace ‘\+’,’ ‘)
    $URI = "https://mvp.support.microsoft.com$($_.Groups[1].Value -replace ‘amp;’,”)"
    while ($ie.Busy -eq $true) { Start-Sleep -Milliseconds 1000; }
    $ie.navigate($URI)
    $URI
    while ($ie.Busy -eq $true) { Start-Sleep -Milliseconds 1000; }
    if (($ie.Document.Body.InnerText.ToString()) -match ‘Results 1 \- \d+ of (\d+)’) {
    $MVPs=""; $MVPs = [int]$matches[1];$MVPs; $obj |Add-Member NoteProperty -Name ‘Count’ -Value ($MVPs)

    }
    $objects += $obj
    }
    $objects |sort Count -Descending |ogv
    [/ps]

    Then Michael B Smith jumped in on the thread, because he thought my script needed some error handling, which is completely right, and came up with his own version of the script.
    [ps]
    Param(
    [switch]$gridview,
    [string]$username,
    [string]$password
    )

    [System.Reflection.Assembly]::LoadWithPartialName("System.Web") | out-null

    $ie = $null

    try
    {
    if ($username)
    {
    $URI = "https://login.live.com/ppsecure/secure.srf?lc=1033&sf=1&id=259214&ru=https://mvp.support.microsoft.com/communities/mvp.aspx&tw=0&fs=0&kv=0&cb=wizid%3df4502d34-3b8f-4a04-b741-289e08aa1782%26lcid%3d1033%26returnurl%3dhttps%253a%252f%252fmvp.support.microsoft.com%252fcommunities%252fmvp.aspx%26brand%3dMicrosoft&cbcxt=&wp=MCMBI&wa=wsignin1.0&wreply=https://mvp.support.microsoft.com/communities/mvp.aspx&wlsu=1"
    $ie = new-object -com "InternetExplorer.Application"
    $ie.visible = $false
    $ie.navigate($URI)
    while ($ie.Busy -eq $true) { Start-Sleep -Milliseconds 1000; }
    $doc = $ie.Document
    $ie.Document.Body.InnerText.ToString()

    $user = $doc.getElementById( "i0116" ) ## login
    if( $user )
    {
    $user.value = $username
    }
    else
    {
    "Document element named ‘Login’ not found"
    }

    $pass = $doc.getElementById( "i0118" ) ## passwd
    if( $pass )
    {
    $pass.value = $password
    }
    else
    {
    "Document element named ‘Passwd’ not found"
    }

    $Logon = $doc.getElementById( "i0011" ) ## SI
    if( $Logon )
    {
    $Logon.click()
    }
    else
    {
    "Document element named ‘SI’ not found"
    }

    $count = 0
    while( $ie.LocationURL -ne "https://mvp.support.microsoft.com/communities/mvp.aspx" )
    {
    if( $ie.LocationURL -eq "https://mvp.support.microsoft.com/mvpinvalidsignin.aspx" )
    {
    write-error "Invalid username / password combination"
    return
    }

    Start-Sleep -Milliseconds 1000
    if( $count -gt 15 )
    {
    "Location URL is $($ie.LocationURL)"
    }
    $count++
    }

    $count = 0
    while( $ie.Busy -eq $true )
    {
    Start-Sleep -Milliseconds 1000
    if( $count -gt 15 )
    {
    "IE still busy after $count seconds"
    }
    $count++
    }

    #$ie.Document.Body.InnerHTML.ToString()
    }

    $regex = [regex]‘(?m)<A href=\"(\/communities\/mvp.aspx\?product=1&amp;competency=(\S+))\"’
    $objects = @()

    $return = $ie.Document.Body.InnerHTML.ToString()
    $regex.Matches($return)|% {
    $obj = New-Object psobject
    $obj |Add-Member NoteProperty -Name ‘Group’ -Value ([System.Web.HttpUtility]::UrlDecode( $_.Groups[2].Value ))

    $URI = "https://mvp.support.microsoft.com$($_.Groups[1].Value -replace ‘amp;’,”)"
    while ($ie.Busy -eq $true) { Start-Sleep -Milliseconds 1000; }
    $ie.navigate($URI)
    $URI
    while ($ie.Busy -eq $true) { Start-Sleep -Milliseconds 1000; }
    if (($ie.Document.Body.InnerText.ToString()) -match ‘Results 1 \- \d+ of (\d+)’) {
    $MVPs=""; $MVPs = [int]$matches[1];$MVPs; $obj |Add-Member NoteProperty -Name ‘Count’ -Value ($MVPs)
    }
    $objects += $obj
    }

    " "
    "Total MVP Competencies $($objects.Count)"
    if( $gridview )
    {
    $objects |sort Count -Descending |ogv
    }
    else
    {
    $objects |sort Count -Descending
    }

    }
    finally
    {
    if( $ie )
    {
    $ie.Quit()
    $ie = $null
    }
    }

    [/ps]

    Finally Kirk Munro decided to go “all in” and more or less rewrite the entire script into reusable functions, and using PSCredentials for more secure handling of the password, rewrote the logic to speed up the script, made it possible to only check a single MVP group and lots more.

    [ps]
    function Get-MvpCount {
    [CmdletBinding()]
    param(
    [Parameter(Position=0,Mandatory=$false)]
    [ValidateNotNullOrEmpty()]
    [System.String[]]
    $Competency = @(‘*’),

    [Parameter(Mandatory=$false)]
    [ValidateRange(0,60)]
    [System.Int32]
    $Timeout = 15,

    [Parameter(Mandatory=$false)]
    [ValidateNotNull()]
    [System.Management.Automation.Credential()]
    $Credential = [System.Management.Automation.PSCredential]::Empty
    )

    #region Initialize and load helper module.
    $helperModule = New-Module -ScriptBlock {
    #region Initialize local variables.
    $ie = $null
    #endregion

    function Show-IEWindow {
    #region Create a new hidden instance of Internet Explorer if one does not exist.
    if (-not $script:ie) {
    $script:ie = New-Object -ComObject ‘InternetExplorer.Application’
    }
    #endregion

    #region Show the IE window.
    $script:ie.Visible = $true
    #endregion
    }

    function Hide-IEWindow {
    #region Create a new hidden instance of Internet Explorer if one does not exist.
    if (-not $script:ie) {
    $script:ie = New-Object -ComObject ‘InternetExplorer.Application’
    }
    #endregion

    #region Hide the IE window.
    $script:ie.Visible = $false
    #endregion
    }

    function Open-IEWebSite {
    [CmdletBinding()]
    param(
    [Parameter(Position=0,Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [System.String]
    $Uri,

    [Parameter(Position=1,Mandatory=$false)]
    [ValidateNotNullOrEmpty()]
    [System.String[]]
    $ErrorUri,

    [Parameter(Mandatory=$false)]
    [ValidateRange(0,60)]
    [System.Int32]
    $Timeout = 15
    )
    #region Create a new hidden instance of Internet Explorer if one does not exist.
    if (-not $script:ie) {
    $script:ie = New-Object -ComObject ‘InternetExplorer.Application’
    $script:ie.Visible = $false
    }
    #endregion

    try {
    #region Navigate to the specified web site.
    Write-Progress -Activity ‘Loading a web page’ -Status "Loading $Uri…"
    $script:ie.Navigate($Uri)
    #endregion

    #region Wait until IE has finished loading the web site.
    $count = 0
    do {
    if ($Timeout -and ($count -gt ($Timeout * 1000))) {
    throw "The $Uri web page failed to load in $Timeout seconds."
    }
    if ((-not $script:ie.Busy) -and $ErrorUri) {
    foreach ($failedLocationUrl in $ErrorUri) {
    if ($script:ie.LocationURL -like $failedLocationUrl) {
    throw "The $Uri web page failed to load ($($script:ie.LocationURL))."
    }
    }
    }
    Start-Sleep -Milliseconds 500
    $count++
    } while ($script:ie.Busy)
    #endregion
    }
    finally {
    if ($script:ie.Busy) {
    $script:ie.Stop()
    }
    Write-Progress -Activity ‘Loading a web page’ -Status "Loading $Uri…" -Completed
    }
    }
    function Test-IEWebSiteElement {
    [CmdletBinding()]
    param(
    [Parameter(Position=0,Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [System.String]
    $Name
    )
    #region Raise an error if you haven’t opened a web site yet.
    if (-not $script:ie.Document) {
    throw ‘You must open a web site using Open-IEWebSite before you can invoke a button on the site.’
    }
    #endregion

    #region Return true if the element exists; false otherwise.
    [bool]$script:ie.Document.getElementById($Name)
    #endregion
    }

    function Set-IEWebSiteFieldData {
    [CmdletBinding()]
    param(
    [Parameter(Position=0,Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [System.Collections.Hashtable]
    $DataMap
    )
    #region Raise an error if you haven’t opened a web site yet.
    if (-not $script:ie.Document) {
    throw ‘You must open a web site using Open-IEWebSite before you can set field data.’
    }
    #endregion

    #region Load the data into the appropriate fields.
    foreach ($key in $DataMap.Keys) {
    if ($field = $script:ie.Document.getElementById($key)) {
    $field.Value = $DataMap[$key]
    } else {
    throw "Field element ‘$key’ was not found on $($script:ie.LocationURL)."
    }
    }
    #endregion
    }
    function Invoke-IEWebSiteButton {
    [CmdletBinding()]
    param(
    [Parameter(Position=0,Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [System.String]
    $Name,

    [Parameter(Position=1,Mandatory=$false)]
    [ValidateNotNullOrEmpty()]
    [System.String[]]
    $ErrorUri,

    [Parameter(Mandatory=$false)]
    [ValidateRange(0,60)]
    [System.Int32]
    $Timeout = 15
    )
    #region Raise an error if you haven’t opened a web site yet.
    if (-not $script:ie.Document) {
    throw ‘You must open a web site using Open-IEWebSite before you can invoke a button on the site.’
    }
    #endregion

    try {
    #region Click on the specified button.
    Write-Progress -Activity ‘Clicking a web site button’ -Status "Clicking on the $Name button on $($script:ie.LocationURL)…"
    if ($button = $script:ie.Document.getElementById($Name)) {
    $button.Click()
    } else {
    throw "Button ‘$Name’ was not found on $($script:ie.LocationURL)."
    }
    #endregion

    #region Wait until IE has finished loading the web site.
    $count = 0
    do {
    if ($Timeout -and ($count -gt ($Timeout * 1000))) {
    throw "The web page failed to load in $Timeout seconds."
    }
    if ((-not $script:ie.Busy) -and $ErrorUri) {
    foreach ($failedLocationUrl in $ErrorUri) {
    if ($script:ie.LocationURL -like $failedLocationUrl) {
    throw "An error occurred ($($script:ie.LocationURL))."
    }
    }
    }
    Start-Sleep -Milliseconds 500
    $count++
    } while ($script:ie.Busy)
    #endregion
    }
    finally {
    if ($script:ie.Busy) {
    $script:ie.Stop()
    }
    Write-Progress -Activity ‘Clicking a web site button’ -Status "Clicking on the $Name button on $($script:ie.LocationURL)…" -Completed
    }
    }
    function Get-IEWebSiteMatch {
    [CmdletBinding()]
    param(
    [Parameter(Position=0,Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [System.Text.RegularExpressions.Regex[]]
    $Regex
    )
    #region Raise an error if you haven’t opened a web site yet.
    if (-not $script:ie.Document) {
    throw ‘You must open a web site using Open-IEWebSite before you can invoke a button on the site.’
    }
    #endregion

    #region Return all matches for the specified regular expression.
    $innerHtml = $script:ie.Document.Body.InnerHTML.ToString()
    foreach ($value in $RegEx) {
    $value.Matches($innerHtml)
    }
    #endregion
    }
    function ConvertFrom-EncodedUrl {
    [CmdletBinding()]
    param(
    [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true)]
    [ValidateNotNullOrEmpty()]
    [System.String[]]
    $InputObject
    )
    begin {
    #region Load the System.Web assembly.
    [System.Reflection.Assembly]::LoadWithPartialName(‘System.Web’) | Out-Null
    #endregion
    }
    process {
    #region Decode the values.
    foreach ($value in $InputObject) {
    [System.Web.HttpUtility]::UrlDecode($value)
    }
    #endregion
    }
    }

    function ConvertTo-EncodedUrl {
    [CmdletBinding()]
    param(
    [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true)]
    [ValidateNotNullOrEmpty()]
    [System.String[]]
    $InputObject
    )
    begin {
    #region Load the System.Web assembly.
    [System.Reflection.Assembly]::LoadWithPartialName(‘System.Web’) | Out-Null
    #endregion
    }
    process {
    #region Encode the values.
    foreach ($value in $InputObject) {
    [System.Web.HttpUtility]::UrlEncode($value)
    }
    #endregion
    }
    }

    $ExecutionContext.SessionState.Module.OnRemove = {
    if ($script:ie) {
    try {
    $script:ie.Quit()
    }
    finally {
    $script:ie = $null
    }
    }
    }
    }
    #endregion

    #region Load the helper module.
    $helperModule | Import-Module
    #endregion

    try {
    #region Open the MVP website, using credentials if they were provided.
    if ($Credential -and ($Credential -ne [System.Management.Automation.PSCredential]::Empty)) {
    #region If the caller provided credentials, use Passport login before retrieving competency data.
    Open-IEWebSite -Uri ‘https://login.live.com/ppsecure/secure.srf?lc=1033&sf=1&id=259214&ru=https://mvp.support.microsoft.com/communities/mvp.aspx&tw=0&fs=0&kv=0&cb=wizid%3df4502d34-3b8f-4a04-b741-289e08aa1782%26lcid%3d1033%26returnurl%3dhttps%253a%252f%252fmvp.support.microsoft.com%252fcommunities%252fmvp.aspx%26brand%3dMicrosoft&cbcxt=&wp=MCMBI&wa=wsignin1.0&wreply=https://mvp.support.microsoft.com/communities/mvp.aspx&wlsu=1′
    if (Test-IEWebSiteElement -Name ‘i0011′) {
    Set-IEWebSiteFieldData -DataMap @{
    ‘i0116′ = $Credential.UserName.Trim([Char[]]’ \’)
    ‘i0118′ = $Credential.GetNetworkCredential().Password
    }
    Invoke-IEWebSiteButton -Name ‘i0011′ -ErrorUri ‘https://mvp.support.microsoft.com/mvpinvalidsignin.aspx’
    }
    #endregion
    } else {
    #region Otherwise, simply open the MVP website.
    Open-IEWebSite -Uri ‘https://mvp.support.microsoft.com/communities/mvp.aspx’
    #endregion
    }
    #endregion

    #region Process the compentencies that were requested.
    Get-IEWebSiteMatch -Regex ‘(?m)<A href=\"(\/communities\/mvp.aspx\?product=1&amp;competency=(\S+))\"’
    | Add-Member -MemberType ScriptProperty -Name DecodedUrl -Value {$this.Groups[2].Value | ConvertFrom-EncodedUrl} -PassThru

    | Sort-Object -Property DecodedUrl
    | ForEach-Object {
    foreach ($value in $Competency) {
    if ($_.DecodedUrl -like $value) {
    Open-IEWebSite -Uri "https://mvp.support.microsoft.com$($_.Groups[1].Value -replace 'amp;','')"
    if ($matches = Get-IEWebSiteMatch -Regex 'Results 1 \- \d+ of (\d+)') {
    $competencyRecord = New-Object -TypeName System.Management.Automation.PSObject

    | Add-Member -MemberType NoteProperty -Name Competency -Value $_.DecodedUrl -PassThru `
    | Add-Member -MemberType NoteProperty -Name Count -Value $matches[0].Groups[1].Value -PassThru
    $competencyRecord.PSTypeNames.Insert(0,’MVPCompetencyRecord’)
    $competencyRecord
    }
    break
    }
    }
    }
    #endregion
    }
    finally {
    $helperModule | Remove-Module
    }
    }
    [/ps]

    Remember this is not thoroughly tested code, this is just examples of different ways of doing things…



  • Translate Service DACL’s

    There was a post on the Minasi forum, where someone was trying to check which users had start/stop permissions on a given server. I knew SC would give the results, but it returns it in DACL format, which as far from readable by humans… So since I had some time to pass I decided to try to write a powershell script to translate the DACL into something human readable (We were having our floor lacquered, and the guy doing it, had a little extra lacquer, and decided to lacquer our hallway, thereby cutting me off from leaving the first floor of our house).

    This function takes a service name and a computername as input, if no computername is given, it tries to look it up on the localmachine.
    [ps]

    Function Get-ServiceDACL {
    [CmdletBinding()]
    param(
    [Parameter(Mandatory=$true,Position=0,ValueFromPipeline=$true)]
    [String]$Servicename,
    [Parameter(Mandatory=$false,Position=1)]
    [String]$Computername= ".")

    $sddl = Invoke-expression -Command "c:\Windows\System32\sc.exe \\$Computername sdshow $Servicename" # $Servicename
    $sddl
    $parts = $sddl -split(":")
    #$parts.Length
    $i = 0
    Write-Host "Getting Service DACL for $ServiceName on $Computername"
    While ($i -lt $parts.length) {

    $part = $parts[$i]

    Switch ($part) {
    "D" { $i++; Parse-DACL $parts[$i] }
    }
    $i++
    }
    $sddl = ”
    }

    Function Parse-DACL {
    Param([String]$SDDLIN)

    [Array]$sddls = ($SDDLIN).split(‘(‘)
    Foreach ($SDDLI in $sddls) {
    #($SDDLI).replace(‘)';”)
    #$SDDLI
    $tokens = (($SDDLI).replace(‘)’,”)).split(";")
    If ($tokens[5]) {
    If ($tokens[5].length -gt 3) {
    [wmi]$obj = ‘Win32_SID.SID="{0}"’ -f $($tokens[5])
    $encoded = [System.Convert]::ToBase64String($obj.BinaryRepresentation)
    $obj | Add-Member -MemberType NoteProperty -Name base64_sid -Value $encoded
    Write-Host "$($obj.ReferencedDomainName)\$($obj.AccountName)" -ForegroundColor red
    }
    Else {
    Write-Host "$($Trustees.get_item($tokens[5]))" -ForegroundColor red
    }
    " " + $AceType.get_item($tokens[0])
    [regex]::split($tokens[2], ‘(.{2})’) | % {Write-host " $($PermissionType.get_item($_)) `n" -NoNewline}
    }
    }
    }

    $AceType = @{"A" = "ACCESS ALLOWED";
    "D" = "ACCESS DENIED";
    "OA" = "OBJECT ACCESS ALLOWED: ONLY APPLIES TO A SUBSET OF THE OBJECT(S).";
    "OD" = "OBJECT ACCESS DENIED: ONLY APPLIES TO A SUBSET OF THE OBJECT(S).";
    "AU" = "SYSTEM AUDIT";
    "AL" = "SYSTEM ALARM";
    "OU" = "OBJECT SYSTEM AUDIT";
    "OL" = "OBJECT SYSTEM ALARM";
    "ML" = "MANDATORY LABEL"}

    $AceFlags = @{
    "CI" = "CONTAINER INHERIT: Child objects that are containers, such as directories, inherit the ACE as an explicit ACE.";
    "OI" = "OBJECT INHERIT: Child objects that are not containers inherit the ACE as an explicit ACE.";
    "NP" = "NO PROPAGATE: ONLY IMMEDIATE CHILDREN INHERIT THIS ACE.";
    "IO" = "INHERITANCE ONLY: ACE DOESN’T APPLY TO THIS OBJECT; BUT MAY AFFECT CHILDREN VIA INHERITANCE.";
    "ID" = "ACE IS INHERITED";
    "SA" = "SUCCESSFUL ACCESS AUDIT";
    "FA" = "FAILED ACCESS AUDIT"
    }

    $PermissionType = @{
    "CC" = "Query Conf";
    "DC" = "Change Conf";
    "LC" = "QueryStat";
    "SW" = "EnumDeps";
    "RP" = "Start";
    "WP" = "Stop";
    "DT" = "Pause";
    "LO" = "Interrogate";
    "CR" = "UserDefined";
    "GA" = "Generic All";
    "GX" = "Generic Execute";
    "GW" = "Generic Write";
    "GR" = "Generic Read";
    "SD" = "Standard Delete";
    "RC" = "Read Control";
    "WD" = "Write DAC";
    "WO" = "Write Owner"
    }

    $Trustees = @{
    "AO" = "Account operators";
    "RU" = "Alias to allow previous Windows 2000";
    "AN" = "Anonymous logon";
    "AU" = "Authenticated users";
    "BA" = "Built-in administrators";
    "BG" = "Built-in guests";
    "BO" = "Backup operators";
    "BU" = "Built-in users";
    "CA" = "Certificate server administrators";
    "CG" = "Creator group";
    "CO" = "Creator owner";
    "DA" = "Domain administrators";
    "DC" = "Domain computers";
    "DD" = "Domain controllers";
    "DG" = "Domain guests";
    "DU" = "Domain users";
    "EA" = "Enterprise administrators";
    "ED" = "Enterprise domain controllers";
    "WD" = "Everyone";
    "PA" = "Group Policy administrators";
    "IU" = "Interactively logged-on user";
    "LA" = "Local administrator";
    "LG" = "Local guest";
    "LS" = "Local service account";
    "SY" = "Local system";
    "NU" = "Network logon user";
    "NO" = "Network configuration operators";
    "NS" = "Network service account";
    "PO" = "Printer operators";
    "PS" = "Personal self";
    "PU" = "Power users";
    "RS" = "RAS servers group";
    "RD" = "Terminal server users";
    "RE" = "Replicator";
    "RC" = "Restricted code";
    "SA" = "Schema administrators";
    "SO" = "Server operators";
    "SU" = "Service logon user"
    }

    #Example below queries the WinRM service on RemoteServer

    Get-ServiceDACL winrm remotemgmt
    [/ps]
    [sourcecode lang="PosH"]
    [/sourcecode]



  • My account keeps getting locked out, where did I use it ??

    A few weeks ago my admin account kept getting locked out, after I had changed my password.. So I assumed I had used it somewhere to either run a service or a scheduled task on a test server. But where???

    So I decided to write a little PowerShell script to help me find out where, and give me a chance to be more proactive next time I need to change my Password, or the password of one of our service accounts.

    So I decided to try to write a script that connects to all our servers, and list all services running under domain credentials, and do the same for scheduled tasks. In our environment we have an issue with some COM+ objects that are either running as a domain admin user, or as “interactive” meaning that a domain admin user has to be logged into a machine at all times for the app to work.. (Yes I have yelled and screamed at the developers).

    So what this script does, it connects info from domain machines, and puts it in a Excel spreadsheet.
    In order to run the script, you need to have Powershell V2, Quest AD cmdlet (preferably ver. 1.2 or above) and permissions on the remote machines to connect via WMI.

    [ps]
    #==========================================================================
    # NAME: GetServiceScheduledtaskandCom.ps1
    #
    # AUTHOR: Claus T Nielsen
    # Version: 0.9
    # Date: 07/09/10
    #
    # COMMENT:
    # This script is based on a script by Stephen Wheet, a lot of the code has been rewritten, and
    # and a bunch of code has been added.
    # The script connects to remote computers, and lists all services running under domain accounts,
    # it does the same for Scheduled Tasks and COM+ Applications.
    #
    # The Script required the QUEST AD cmdlets and excel installed on the computer
    #
    # Missing features: IIS APP Pool Credentials, Logged In Users
    #==========================================================================
    $domainname = (Get-QADRootDSE.Domain).Domain.ToString()

    $searchroot = "appension.local/"

    $ErrorActionPreference = "SilentlyContinue"

    [System.Threading.Thread]::CurrentThread.CurrentCulture = "en-US"
    $ErrorActionPreference = "SilentlyContinue"
    $ExcelAPP = New-Object -comobject Excel.Application
    $ExcelAPP.visible = $True

    $ExcelWB = $ExcelAPP.Workbooks.Add()
    $ServiceSheet = $ExcelWB.Worksheets.Item(1)
    $ScheduledSheet = $ExcelWB.Worksheets.Item(2)
    $COMPlusSheet = $ExcelWB.Worksheets.Item(3)

    $ServiceSheet.Name = "Services"
    $ScheduledSheet.Name = "Scheduled Tasks"
    $COMPlusSheet.Name = "COM+"

    # Accounts to ignore
    $IgnoreAcct =
    "NT AUTHORITY\LOCAL SERVICE",
    "NT AUTHORITY\LOCALSERVICE",
    "LocalSystem",
    ".\*",
    "NT AUTHORITY\NETWORK SERVICE",
    "NT AUTHORITY\NetworkService"

    $DefaultCOMObjects =
    ‘COM+ Utilities’,
    ‘COM+ QC Dead Letter Queue Listener’,
    ‘COM+ Explorer’,
    ‘COM+ Utilities (32 bit)’,
    ‘IIS Out-Of-Process Pooled Applications’,
    ‘.NET Utilities’

    #Place Headers on out-put file

    $ServiceSheet.Cells.Item(1,1) = "Server"
    $ServiceSheet.Cells.Item(1,2) = "Service"
    $ServiceSheet.Cells.Item(1,3) = "Account"

    $ScheduledSheet.Cells.Item(1,1) = "Server"
    $ScheduledSheet.Cells.Item(1,2) = "Task"
    $ScheduledSheet.Cells.Item(1,3) = "Next Run Time"
    $ScheduledSheet.Cells.Item(1,4) = "Account"

    $COMPlusSheet.Cells.Item(1,1) = "Server"
    $COMPlusSheet.Cells.Item(1,2) = "COM+ Name"
    $COMPlusSheet.Cells.Item(1,3) = "Identity"

    $d = $ServiceSheet.UsedRange
    $d.Interior.ColorIndex = 19
    $d.Font.ColorIndex = 11
    $d.Font.Bold = $True

    $l = $ScheduledSheet.UsedRange
    $l.Interior.ColorIndex = 19
    $l.Font.ColorIndex = 11
    $l.Font.Bold = $True

    $q = $COMPlusSheet.UsedRange
    $q.Interior.ColorIndex = 19
    $q.Font.ColorIndex = 11
    $q.Font.Bold = $True

    $intRowSer = 2
    $intRowSch = 2
    $intRowCom = 2

    #Get all the servers from the specified OU
    $Servers = get-QADComputer -SearchRoot $searchroot -OSName "*Server*" #| where {$_.name -like "appo*"} # change the container based on site.

    Foreach ($server in $Servers ) {
    #$ErrorActionPreference = "SilentlyContinue"
    $serverFQDN = $server.dnsname
    #Test ping server to make sure it’s up before querying it
    if (Test-Connection $serverFQDN -Quiet -Count 1){
    Write-Host "n ************* $serverFQDN Online n" -ForegroundColor Red
    Write-Host "****************** $($server.name) Services ******************"
    # Get service info
    $error.clear()
    $services = gwmi win32_service -computer $serverFQDN -property name, startname, caption |
    % {

    $name = $_.Caption
    $Acctname = $_.StartName
    If ( $IgnoreAcct -notcontains $Acctname )
    {
    Write-host "$Name $Acctname"
    $ServiceSheet.Cells.Item($intRowSer, 1) = $serverFQDN
    $ServiceSheet.Cells.Item($intRowSer, 2) = $name
    $ServiceSheet.Cells.Item($intRowSer, 3) = $Acctname
    $intRowSer++
    } #end If

    } #end ForEach

    #Write log if no access
    if (!$?) {
    $ServiceSheet.Cells.Item($intRowSer, 1) = $serverFQDN
    $ServiceSheet.Cells.item($intRowSer, 2).Interior.ColorIndex = 3
    $ServiceSheet.Cells.Item($intRowSer, 2) = "Access Denied/Offline"
    $ServiceSheet.Cells.Item($intRowSer, 3) = $Error
    #$errmsg = "$serverFQDN,No RPC server,ACCESS DENIED"
    Write-Host $Error
    $intRowSer++
    } # end Error

    $schtask = Schtasks.exe /query /s $serverFQDN /V /FO CSV | ConvertFrom-Csv
    Write-Host "****************** $($server.name) Scheduled Tasks ******************"
    if ($schtask) {

    Foreach ($sch in $schtask) {
    #$Sch."Run As User"
    if ($Sch."Run As User" -like "$($domainname)*") {
    Write-Host $serverFQDN ($Sch.TaskName).replace("\","") $Sch.’Run As User’

    $ScheduledSheet.Cells.Item($intRowSch,1) = $serverFQDN
    $ScheduledSheet.Cells.Item($intRowSch,2) = ($sch.TaskName).replace(‘\’,”)
    $ScheduledSheet.Cells.Item($intRowSch,3) = $Sch.’Next Run Time’
    $ScheduledSheet.Cells.Item($intRowSch,4) = $sch.’Run As User’
    $intRowSch++

    }

    }
    }
    Write-Host "****************** $($server.name) COM+ Applications ******************"
    #$targetComputer = $serverFQDN
    $comAdmin = New-Object -comobject COMAdmin.COMAdminCatalog
    $comAdmin.Connect($serverFQDN)
    $apps = $comAdmin.GetCollection("Applications")

    $apps.Populate()

    foreach ($app in $apps) {
    If ( $IgnoreAcct -notcontains ($app.Value("Identity")) -and ( $DefaultCOMObjects -notcontains ($app.Value("Name")) )) {
    $q.Cells.Item($intRowCom,1) = $serverFQDN
    $q.Cells.Item($intRowCom,2) = $app.Value("Name")
    $q.Cells.Item($intRowCom,3) = $app.Value("Identity")
    Write-Host $app.Value("Name") $app.Value("Identity")
    $intRowCom++
    }
    }
    }

    Else
    {
    Write-Host "$serverFQDN ************* OFFLINE"
    } #end Else
    }
    #end ForEach
    $d.EntireColumn.AutoFit()
    $l.EntireColumn.AutoFit()
    $q.EntireColumn.AutoFit()
    [/ps]



  • Output a sortable HTML table

    A while back I posted a script that would take whatever input it got, into a sortable HTML table in a file.

    Last night my family was here, and they wanted to see the Eurovision song contest thing, so I had some time to rewrite the script into a PowerShell V2 Advanced function, that supports pipeline input.

    There are some examples in the code on how to use the function

    I do not know what has happened to code highlighter, but it has suddenly decided to mess up the code, so it is not working on the site, so here is a link to the file.

    Out-HTMLTable

    Example of output:

    Out-HTMLTable example

    download | new post



  • Remoting examples from my presentation

    Example #1

    [ps]
    #Sessions

    #Single Session
    $Session = New-PSSession -ComputerName "computername"

    #Multiple Sessions

    $Session = New-PSSession -ComputerName "comp1","comp2"…..

    #Remove all Sessions

    Remove-PSSession *

    #Remove Named Session

    Remove-PSSession $Session

    #Using $session
    Invoke-Command {ipconfig} -Session $Session

    Enter-PSSession -Session $session
    [/sourcecode]

    Example #2

    [sourcecode lang="PosH"]
    $session = New-PSSession -ComputerName "compname"

    Invoke-Command {Import-Module ActiveDirectory} -Session $session

    Import-PSSession -Session $session -Module ActiveDirectory -Prefix "ctn"

    notepad (Get-Module).path

    Get-Command *ctn*

    [/ps]



  • Quest AD Cmdlet examples from my Presentation

    Example #1
    List users that expires within X days
    [ps]
    $DaysToExpire = 14
    $MaxPassAge = (Get-QADObject (Get-QADRootDSE).defaultNamingContextDN).MaximumPasswordAge.days
    [array]$a = Get-QADUser -Enabled -PasswordNeverExpires:$false -SizeLimit 0 -Email * |Select-Object Name,Email,@{Name="Expires";Expression={ $MaxPassAge – $_.PasswordAge.days }} | where {$_.Expires -lt 0} | Sort-Object expires
    [/ps]

    Example #2
    Locate that Hyper-V Host
    [ps]
    Get-QADComputer | Where {$_.OSname -match "2008"} | % { Get-Service -ComputerName $_.Name} | where {$_.Displayname -match "hyper"} | select Machinename, Displayname

    #Kirk Munroe pointed out that Hyper-V actually registers ans SCP (Service Connection Point)
    Get-QADObject -Name ‘Microsoft Hyper-V’ -Type serviceConnectionPoint | Get-QADComputer -Identity {$_.ParentContainerDN}
    [/ps]

    Example #3
    Create test users and OU’s in AD
    [ps]
    #Gets the default naming context
    $RootDN = (Get-QADRootDSE).DefaultNamingContextDN
    #Name of OU going to be created in the root of "AD"
    $RootOUName = "MinasiTest"
    #Create "root" OU
    new-qadObject -ParentContainer $RootDN -type ‘organizationalUnit’ -NamingProperty ‘ou’ -name $RootOUName
    #Create sub OU’s, create as many as you like, you only need to change the -name property in the end of the line
    new-qadObject -ParentContainer "OU=$RootOUName,$RootDN" -type ‘organizationalUnit’ -NamingProperty ‘ou’ -name ‘Administrators’
    new-qadObject -ParentContainer "OU=$RootOUName,$RootDN" -type ‘organizationalUnit’ -NamingProperty ‘ou’ -name ‘Marketing’
    new-qadObject -ParentContainer "OU=$RootOUName,$RootDN" -type ‘organizationalUnit’ -NamingProperty ‘ou’ -name ‘Sales’
    new-qadObject -ParentContainer "OU=$RootOUName,$RootDN" -type ‘organizationalUnit’ -NamingProperty ‘ou’ -name ‘IT’
    new-qadObject -ParentContainer "OU=$RootOUName,$RootDN" -type ‘organizationalUnit’ -NamingProperty ‘ou’ -name ‘HR’

    #
    #
    #
    #Enter the DN path of the OU you want to add users to
    #Note I manually put in the DN of an OU in my test environment, you will have to put one in that exists in your environment

    #$OuPath = ‘OU=Aprismo Users,DC=aprismo,DC=test’
    $OuPath = "OU=$RootOUName,$RootDN"

    #Number of users to create in each OU

    $No = 5

    Function AddUsers
    {
    param([string]$OUDN, [string]$OUName)

    foreach($user in 1..$No)
    {
    $UserName = "Test$OUName$User"
    $UserPassword = "P@ssw0rd123!"
    $ExpiresOn = $((Get-Date).AddMonths(1))
    $userDescription = "User added for Performance Testing on $(Get-date) and Expires on $ExpiresOn"

    $user = New-QADUser -name $UserName
    -SamAccountName $UserName

    -Description $UserDescription
    -ParentContainer $OUDN

    -UserPassword $UserPassword

    $user | Set-QADUser -AccountExpires ((Get-Date).AddMonths(1))
    }
    }

    #This foreach loops through all OU’s "below" $OUPath
    Foreach ($OU in Get-QADObject -SearchRoot $OUPath -Type ‘organizationalUnit’){
    Addusers $OU.DN $OU.Name
    }

    [/pa]

    Example #4
    Rename Groups in AD
    [ps]
    Get-QADGroup -Name "xyz*" | %{Set-QADGroup -Identity $_ -SamAccountName ($_.Name).Replace("xyz","abc") -whatif ;Rename-QADObject -Identity $_ -NewName ($_.Name).Replace("xyz","abc") -WhatIf }
    [/ps]

    Example #5
    Output a list of servers in a Excel documents, with ping stats and if the machine is disabled/enabled
    [ps][/ps]
    #$serverlist = Get-QADComputer -LdapFilter ‘(!(userAccountControl:1.2.840.113556.1.4.803:=2))’ | where {$_.Osname -like “*server*”}
    $serverlist = Get-QADComputer -IncludedProperties pwdLastSet -SizeLimit 0 | where {$_.Osname -like “*server*”}

    $erroractionpreference = “SilentlyContinue”
    $a = New-Object -comobject Excel.Application
    $a.visible = $True

    $b = $a.Workbooks.Add()
    $c = $b.Worksheets.Item(1)

    $c.Cells.Item(1,1) = “Machine Name”
    $c.Cells.Item(1,2) = “OS Name”
    $c.Cells.Item(1,3) = “IP Address”
    $c.Cells.Item(1,4) = “Ping Status”
    $c.Cells.Item(1,5) = “Password last set”
    $c.Cells.Item(1,6) = “Enabled/Disabled”
    $c.Cells.Item(1,7) = “Physical/Virtual”

    $d = $c.UsedRange
    $d.Interior.ColorIndex = 19
    $d.Font.ColorIndex = 11
    $d.Font.Bold = $True

    $intRow = 2

    $colComputers = $serverlist
    foreach ($strComputer in $colComputers)
    {
    $c.Cells.Item($intRow, 1) = $strComputer.Name

    $ping = new-object System.Net.NetworkInformation.Ping
    $Reply = $ping.send($strComputer.Name)

    if ($Reply.status –eq “Success”)
    {
    $machineType = Get-WmiObject -ComputerName $strComputer.Name -Class Win32_BIOS

    If ($strComputer.AccountIsDisabled) {$enab = “Disabled”} else {$enab = “Enabled”}
    if ($strComputer.pwdLastSet -le (Get-Date).AddDays(-90)) {$age = “Older than 90 Days” ; $fgColor = 3} else {$age = “Less than 90 days”; $fgColor = 0}

    if ($machineType.Serialnumber -like “*vmware*”) {$type = “VMware”}
    Elseif ($machineType.Version -like “*VRTUAL*”) {$type = “Hyper-V”}
    Elseif (!($machineType.Version)) {$type = “N/A”}
    else {$type = “Physical”}

    $c.Cells.Item($intRow, 2) = $strComputer.OSName
    $c.Cells.Item($intRow, 3) = $Reply.Address.ToString()
    $c.Cells.Item($intRow, 4) = “Online”
    $c.Cells.item($intRow, 5).Interior.ColorIndex = $fgColor
    $c.Cells.Item($intRow, 5) = $age
    $c.Cells.Item($intRow, 6) = $enab
    $c.Cells.Item($intRow, 7) = $type
    $Reply = “”
    $intRow = $intRow + 1

    }
    else
    {
    $machineType = Get-WmiObject -ComputerName $strComputer.Name -Class Win32_BIOS

    If ($strComputer.AccountIsDisabled) {$enab = “Disabled”} else {$enab = “Enabled”}
    if ($strComputer.pwdLastSet -le (Get-Date).AddDays(-90)) {$age = “Older than 90 Days” ; $fgColor = 3} else {$age = “Less than 90 days”; $fgColor = 0}
    if ($machineType.Serialnumber -like “*vmware*”) {$type = “VMware”}
    Elseif (!($machineType.Version)) {$type = “N/A”}
    Elseif ($machineType.Version -like “*VRTUAL*”) {$type = “Hyper-V”}
    else {$type = “Physical”}

    $c.Cells.Item($intRow, 2) = $strComputer.OSName
    $c.Cells.Item($intRow, 3) = $Reply.Address.ToString()
    $c.Cells.Item($intRow, 4) = “Offline”
    $c.Cells.item($intRow, 5).Interior.ColorIndex = $fgColor
    $c.Cells.Item($intRow, 5) = $age
    $c.Cells.Item($intRow, 6) = $enab
    $c.Cells.Item($intRow, 7) = $type
    $Reply = “”

    $intRow = $intRow + 1

    }
    $d.EntireColumn.AutoFit()

    }
    [ps][/ps]



  • .Net Examples from Presentation

    Example #1 (From Lee Holmes’ Powershell cookbook)

    “Compile C# code on the fly”
    [ps]

    $code =@’
    using System.Management.Automation;

    [Cmdlet("Write", "InputObject")]
    public class MyWriteInputObjectCmdlet : Cmdlet
    {
    [Parameter]
    public string Parameter1;

    [Parameter(Mandatory = true, ValueFromPipeline=true)]
    public string InputObject;

    protected override void ProcessRecord()
    {
    if (Parameter1 != null)
    WriteObject(Parameter1 + ":" + InputObject);
    else
    WriteObject(InputObject);
    }
    }
    ‘@

    Add-Type -TypeDefinition $code -OutputAssembly .\ExampleModule.dll

    Import-Module .\ExampleModule.dll

    [/ps]

    Example #2 (From Lee Holmes’ Powershell cookbook)
    Showing how static functions are available directly

    [ps]
    $source = @"
    public class BasicTest
    {
    public static int Add(int a, int b)
    {
    return (a + b);
    }

    public int Multiply(int a, int b)
    {
    return (a * b);
    }
    }
    "@

    Add-Type -TypeDefinition $source

    [BasicTest]::Add(4, 3)

    $basicTestObject = New-Object BasicTest
    $basicTestObject.Multiply(5, 2)
    [/ps]

    Example #3
    Access .Net function to move mouse, in order to prevent screensaver from kicking in.
    [ps]
    Function Move-Mouse {

    param($minutes = 60)

    for ($i = 0; $i -lt $minutes; $i++) {
    Start-Sleep -Seconds 60
    $Pos = [System.Windows.Forms.Cursor]::Position
    [System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point((($Pos.X) + 1) , $Pos.Y)

    }
    }

    [/ps]



  • Profile Examples from Presentation

    Here are some of the scripts that I used during the demonstration in VA Beach.

    Profiles:

    Example #1

    [ps]
    function prompt
    {
    "Xenophane " + $(get-location) + ">"
    }
    [/ps]

    Example #2

    [ps]
    function prompt
    {
    "Processes " + (Get-Process).Count+ " " + $(get-location) + "> "
    }
    [/ps]

    Example #3 (Example taken from website)

    [ps]
    function Prompt
    {
    $id = 1
    $historyItem = Get-History -Count 1
    if($historyItem)
    {
    $id = $historyItem.Id + 1
    }

    Write-Host -ForegroundColor DarkGray n[$(Get-Location)]
    Write-Host -NoNewLine PS$id
    $host.UI.RawUI.WindowTitle = $(Get-Location)

    b
    }
    [/ps]

    Example #4 (Overdone one)

    [ps]
    function prompt
    {
    [wmi]$Global:Cdrive=Get-WmiObject -query "Select * from win32_logicaldisk where deviceid=’c:’"
    #Define Cdrive as global variable, which is type cast as a wmi
    $processcount=(Get-Process).Count
    #Define variable processcount as number of processes running
    $cpuload=(Get-WmiObject win32_processor).loadpercentage
    #cpuload is defined as a variable
    $diskinfoC=" Free C: "+"{0:N2}" -f (($global:Cdrive.freespace/1gb)/($global:cdrive.size/1gb)*100)+"%"
    #diskinfoC is defined, {0:N2} is .NET for 2 decimal places, -f is a the "format" property of the string object.
    # Then the amount of free space on drive C is divided by the size of drive C multiplies by 100 to get
    #the percentage of free space.
    $time=Get-WmiObject -class Win32_OperatingSystem
    #Define $time is object Win32_OperatingSystem
    $t=$time.ConvertToDateTime($time.Lastbootuptime)
    #Define #t as the result of the convertion of LastBootuptime into a readable dateTime format.
    [TimeSpan]$uptime=New-TimeSpan $t $(get-date)
    #Typecast the variable $uptime as a [timespan], the timespan cmdlet in powershell is a way to do date arithmetic in ps
    #This way we can compare our variable $t (Which was Lastbootuptime) and the current time Get-date cmdlet
    $up="$($uptime.days)d $($uptime.hours)h $($uptime.minutes)m $($uptime.seconds)s"
    #define variable $up to display the uptime in days/hours/minuted/seconds
    $TextToDisplay="CPU:"+$cpuload+"% Processes:" + $processcount + $diskinfoC+ " " + $diskinfoG+ " "+ ([char]0x25b2)+$up +" "+(Get-Date -format g)
    #define one variable that contains all the data we collected so far.
    Write-Host -fore red $TextToDisplay
    #Write the information to the screen in red
    Write-Host "My PoSh:" $(get-location) -nonewline
    #Display the regular prompt.
    }

    [/ps]