+menu-


  • Change username/password on scheduled tasks.

    As stated in a previous post, I have been working on a script to change passwords on scheduled tasks.

    I had hoped to find some time to clean up the code, and write some error handling, but a few people asked for the code, so here it is in alpha alpha edition.

    ToDo:
    Tidy up code
    Add some error handling
    Add code to update-scheduledtasks created in 2k8(R2) GUI

    Description:

    The script is assuming you have  Powershell V2, and Quest AD cmdlets.

    Here is a picture of the GUI when you run the script.

    The Quest AD cmdlets are used to connect to AD, to get a list of computers to check for scheduled tasks

    image

    Search Account:  Search for scheduled tasks running under the supplied account, you can use wildcards. If you supply DomainName\* (Default value), then it will search for scheduled tasks running under a domain account, you Search Root: The DN path from where you want to build your computer list

    OSName: Default value is *server* it’s the value that is the same for all windows servers… So with this value set, it will only return servers from AD

    Filter MachineName: Default value is “*” which returns all servers,  example “Exchan*” would return all servers whose names start with “Exchan”

    PassWord: Enter the new password for the scheduled tasks.

    The Run scheduled tasks with current credentials is not working, since it is not supported against 2003 servers and below, so I remove the functionality.

     

    Here is an example of a result.

    image

    You can click on one and edit the username if you like, otherwise you can just mark the ones you want to change password on, holding down ctrl and click each one.

    image

    Press Change PWD

     

    As stated above, there is no particular error handling,and it takes a while to run depending on how many servers you have.  (I hope to find some time to update the script, to a more “production” ready state soon)

    ########################################################################
    # Code Generated By: SAPIEN Technologies, Inc., PrimalForms 2009 v1.1.11.0
    # Generated On: 29-01-2011 23:05
    # Generated By: CTN
    ########################################################################
    
    #----------------------------------------------
    #region Application Functions
    #----------------------------------------------
    
    function OnApplicationLoad {
    	#Note: This function runs before the form is created
    	#Note: To get the script directory in the Packager use: Split-Path $hostinvocation.MyCommand.path
    	#Note: To get the console output in the Packager (Windows Mode) use: $ConsoleOutput (Type: System.Collections.ArrayList)
    	#Important: Form controls cannot be accessed in this function
    	#TODO: Add snapins and custom code to validate the application load
    	
    	return $true #return true for success or false for failure
    }
    
    function OnApplicationExit {
    	#Note: This function runs after the form is closed
    	#TODO: Add custom code to clean up and unload snapins when the application exits
    	
    	$script:ExitCode = 0 #Set the exit code for the Packager
    }
    
    #endregion
    
    #----------------------------------------------
    # Generated Form Function
    #----------------------------------------------
    function GenerateForm {
    
    	#----------------------------------------------
    	#region Import Assemblies
    	#----------------------------------------------
    	[void][reflection.assembly]::Load("System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
    	[void][reflection.assembly]::Load("System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
    	[void][reflection.assembly]::Load("mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
    	[void][reflection.assembly]::Load("System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
    	#endregion
    	
    	#----------------------------------------------
    	#region Generated Form Objects
    	#----------------------------------------------
    	[System.Windows.Forms.Application]::EnableVisualStyles()
    	$form1 = New-Object System.Windows.Forms.Form
    	$progressbar1 = New-Object System.Windows.Forms.ProgressBar
    	$label9 = New-Object System.Windows.Forms.Label
    	$SchTaskPWD = New-Object System.Windows.Forms.TextBox
    	$label8 = New-Object System.Windows.Forms.Label
    	$button4 = New-Object System.Windows.Forms.Button
    	$label7 = New-Object System.Windows.Forms.Label
    	$SchTaskUsr = New-Object System.Windows.Forms.TextBox
    	$button3 = New-Object System.Windows.Forms.Button
    	$label6 = New-Object System.Windows.Forms.Label
    	$srchMachineNameTXT = New-Object System.Windows.Forms.TextBox
    	$label5 = New-Object System.Windows.Forms.Label
    	$SrchOSNameTXT = New-Object System.Windows.Forms.TextBox
    	$label4 = New-Object System.Windows.Forms.Label
    	$SrchRootTXT = New-Object System.Windows.Forms.TextBox
    	$label2 = New-Object System.Windows.Forms.Label
    	$SrchAccountTxt = New-Object System.Windows.Forms.TextBox
    	$label1 = New-Object System.Windows.Forms.Label
    	$textbox1 = New-Object System.Windows.Forms.TextBox
    	$button2 = New-Object System.Windows.Forms.Button
    	$datagridview1 = New-Object System.Windows.Forms.DataGridView
    	$button1 = New-Object System.Windows.Forms.Button
    	$tooltip1 = New-Object System.Windows.Forms.ToolTip
    	$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
    	#endregion Generated Form Objects
    
    	#----------------------------------------------
    	# User Generated Script
    	#----------------------------------------------
    
    	
    	
    	
    	
    	$FormEvent_Load={
    		#TODO: Initialize Form Controls here
    		$erroractionpreference = "SilentlyContinue"
    		Add-PSSnapin *quest*
    		$domainname = (Get-QADRootDSE).Domain.ToString()
    		$SrchAccountTxt.Text = "$domainname" + "*"
    		
    		$SrchRootTXT.Text = (Get-QADRootDSE).DefaultNamingContextDN.ToString()
    		$SrchOSNameTXT.Text = "*Server*"
    		$srchMachineNameTXT.Text = "*"
    		$SchTaskUsr.text = $env:userdomain + "\" + $env:username
    		$array= new-object System.Collections.ArrayList
    		$Tasks = @()
    	 
    	 
    	 
    	}
    	
    	
    	$handler_button1_Click={
    	#TODO: Place custom script here
    	
    	
    	
    	$Servers = get-QADComputer -SearchRoot $SrchRootTXT.Text -OSName $SrchOSNameTXT.Text -Name $srchMachineNameTXT.Text # | where {$_.name -like $($srchMachineNameTXT.Text)}
    	$progressbar1.Maximum = $Servers.Length
    	
    	
    	Foreach ($server in $Servers ) {
    	$serverFQDN = $server.dnsname
    	
    	
    	$progressbar1.value += 1 
    	
    	
    	
    	$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'
    	
    	
    		$SchedTasks = New-Object System.Object
    		$SchedTasks | Add-Member -type NoteProperty -name ServerName -value $serverFQDN
    		$SchedTasks | Add-Member -type NoteProperty -name "Scheduled Task" -value ($Sch.TaskName).replace("\","")
    		$SchedTasks | Add-Member -type NoteProperty -name NextRun  -value $Sch.'Next Run Time' 
    		$SchedTasks | Add-Member -type NoteProperty -name Username  -value $sch.'Run As User' 
    		$Tasks  += $SchedTasks
    		$SchedTasks
    		
    	
    	}
    	
    	}
    	
    	}
    	
    	}
    	
    	
    	$array.AddRange($tasks) 
    	$datagridview1.DataSource = $array
    	$datagridview1.AutoResizeColumns()
    	
    	}
    	$handler_button2_Click={
    		foreach ($row in $datagridview1.SelectedRows) {
    		#[System.Windows.Forms.MessageBox]::Show($row.Cells[0].Value)
    		$StrCmd = schtasks.exe /change /s "$($row.Cells[0].Value)" /RU "$($row.Cells[3].Value)" /RP "$($textbox1.text)" /TN "`"$($row.Cells[1].Value)`""		
    			#Invoke-Expression $strCmd #|Out-File c:\temp\userlog.txt
    			Write-Host $LastExitCode
    			Write-Host $StrCmd
    			Clear-Variable StrCmd -ErrorAction SilentlyContinue
    	
    		}
    		
    	}
    	
    	$handler_label1_Click={
    	#TODO: Place custom script here
    	
    	}
    	
    	$handler_label2_Click={
    	#TODO: Place custom script here
    	
    	}
    	
    	$handler_button3_Click={
    	#TODO: Place custom script here
    	if ($textbox1.PasswordChar -notlike "`0" ) {$textbox1.PasswordChar = $null ;$textBox1.Text = $textBox1.Text}
    	else  {$textbox1.PasswordChar = "*";$textBox1.Text = $textBox1.Text}
    	
    	}
    	
    	$handler_label7_Click={
    	#TODO: Place custom script here
    	
    	}
    	
    	
    	
    	$handler_tooltip1_Popup=[System.Windows.Forms.PopupEventHandler]{
    	#Event Argument: $_ = [System.Windows.Forms.PopupEventArgs]
    	#TODO: Place custom script here
    	
    	}
    	
    	$ShowHelp={
    	#TODO: Place custom script here
    	#display popup help
    	Switch ($this.name) {
    	"SrchAccountTxt" {$tip="Examples: `n Domainname\AdminGuy Search for a specific account.`n DomainName\admin* For all usersnames in the domain that starts with admin `n Domainname\* All Domain users"}
    	"SrchRootTXT" {$tip="Enter DN for the OU, that you want to be the base of the AD search"}
    	"SrchOSNameTXT"  {$tip="Enter a complete or partial machinename that you want to search for. Wildcards are permitted `n Exhange* will find all servers whos name starts with 'Exchange'"}
    	default {$tip="No help found for $($this.name)"}
    	}
    	$tooltip1.SetToolTip($this,$tip)
    	
    	}
    	
    	$handler_button4_Click={
    	#TODO: Place custom script here
    	if ($SchTaskPWD.PasswordChar -notlike "`0" ) {$SchTaskPWD.PasswordChar = $null ;$SchTaskPWD.Text = $SchTaskPWD.Text}
    	else  {$SchTaskPWD.PasswordChar = "*";$SchTaskPWD.Text = $SchTaskPWD.Text}
    	}
    	
    	
    	
    	#----------------------------------------------
    	# Generated Events
    	#----------------------------------------------
    	
    	$Form_StateCorrection_Load=
    	{
    		#Correct the initial state of the form to prevent the .Net maximized form issue
    		$form1.WindowState = $InitialFormWindowState
    	}
    	
    	#----------------------------------------------
    	#region Generated Form Code
    	#----------------------------------------------
    	#
    	# form1
    	#
    	$form1.Controls.Add($progressbar1)
    	$form1.Controls.Add($label9)
    	$form1.Controls.Add($SchTaskPWD)
    	$form1.Controls.Add($label8)
    	$form1.Controls.Add($button4)
    	$form1.Controls.Add($label7)
    	$form1.Controls.Add($SchTaskUsr)
    	$form1.Controls.Add($button3)
    	$form1.Controls.Add($label6)
    	$form1.Controls.Add($srchMachineNameTXT)
    	$form1.Controls.Add($label5)
    	$form1.Controls.Add($SrchOSNameTXT)
    	$form1.Controls.Add($label4)
    	$form1.Controls.Add($SrchRootTXT)
    	$form1.Controls.Add($label2)
    	$form1.Controls.Add($SrchAccountTxt)
    	$form1.Controls.Add($label1)
    	$form1.Controls.Add($textbox1)
    	$form1.Controls.Add($button2)
    	$form1.Controls.Add($datagridview1)
    	$form1.Controls.Add($button1)
    	$form1.ClientSize = New-Object System.Drawing.Size(897,567)
    	$form1.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$form1.Name = "form1"
    	$form1.Text = "Change Scheduled Task Passwords v. 0.0.1"
    	$form1.add_Load($FormEvent_Load)
    	#
    	# progressbar1
    	#
    	$progressbar1.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$progressbar1.Location = New-Object System.Drawing.Point(34,528)
    	$progressbar1.Name = "progressbar1"
    	$progressbar1.Size = New-Object System.Drawing.Size(829,23)
    	$progressbar1.TabIndex = 23
    	#
    	# label9
    	#
    	$label9.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$label9.Location = New-Object System.Drawing.Point(505,98)
    	$label9.Name = "label9"
    	$label9.Size = New-Object System.Drawing.Size(108,23)
    	$label9.TabIndex = 22
    	$label9.Text = "Schtasks Password"
    	#
    	# SchTaskPWD
    	#
    	$SchTaskPWD.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$SchTaskPWD.Location = New-Object System.Drawing.Point(619,95)
    	$SchTaskPWD.Name = "SchTaskPWD"
    	$SchTaskPWD.PasswordChar = '*'
    	$SchTaskPWD.Size = New-Object System.Drawing.Size(161,20)
    	$SchTaskPWD.TabIndex = 21
    	#
    	# label8
    	#
    	$label8.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$label8.Location = New-Object System.Drawing.Point(505,64)
    	$label8.Name = "label8"
    	$label8.Size = New-Object System.Drawing.Size(108,23)
    	$label8.TabIndex = 20
    	$label8.Text = "Schtasks username"
    	#
    	# button4
    	#
    	$button4.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$button4.Location = New-Object System.Drawing.Point(786,93)
    	$button4.Name = "button4"
    	$button4.Size = New-Object System.Drawing.Size(81,23)
    	$button4.TabIndex = 19
    	$button4.Text = "Toggle PWD"
    	$button4.UseVisualStyleBackColor = $True
    	$button4.add_Click($handler_button4_Click)
    	#
    	# label7
    	#
    	$label7.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$label7.Location = New-Object System.Drawing.Point(506,36)
    	$label7.Name = "label7"
    	$label7.Size = New-Object System.Drawing.Size(218,23)
    	$label7.TabIndex = 18
    	$label7.Text = "Run Schtasks with following credentials"
    	#
    	# SchTaskUsr
    	#
    	$SchTaskUsr.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$SchTaskUsr.Location = New-Object System.Drawing.Point(619,63)
    	$SchTaskUsr.Name = "SchTaskUsr"
    	$SchTaskUsr.Size = New-Object System.Drawing.Size(161,20)
    	$SchTaskUsr.TabIndex = 17
    	#
    	# button3
    	#
    	$button3.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$button3.Location = New-Object System.Drawing.Point(439,123)
    	$button3.Name = "button3"
    	$button3.Size = New-Object System.Drawing.Size(79,23)
    	$button3.TabIndex = 16
    	$button3.Text = "Toggle PWD"
    	$button3.UseVisualStyleBackColor = $True
    	$button3.add_Click($handler_button3_Click)
    	#
    	# label6
    	#
    	$label6.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$label6.Location = New-Object System.Drawing.Point(169,92)
    	$label6.Name = "label6"
    	$label6.Size = New-Object System.Drawing.Size(106,23)
    	$label6.TabIndex = 15
    	$label6.Text = "Filter MachineName"
    	#
    	# srchMachineNameTXT
    	#
    	$srchMachineNameTXT.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$srchMachineNameTXT.Location = New-Object System.Drawing.Point(284,92)
    	$srchMachineNameTXT.Name = "srchMachineNameTXT"
    	$srchMachineNameTXT.Size = New-Object System.Drawing.Size(148,20)
    	$srchMachineNameTXT.TabIndex = 14
    	#
    	# label5
    	#
    	$label5.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$label5.Location = New-Object System.Drawing.Point(172,66)
    	$label5.Name = "label5"
    	$label5.Size = New-Object System.Drawing.Size(101,23)
    	$label5.TabIndex = 13
    	$label5.Text = "OS Name"
    	#
    	# SrchOSNameTXT
    	#
    	$SrchOSNameTXT.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$SrchOSNameTXT.Location = New-Object System.Drawing.Point(284,66)
    	$SrchOSNameTXT.Name = "SrchOSNameTXT"
    	$SrchOSNameTXT.Size = New-Object System.Drawing.Size(148,20)
    	$SrchOSNameTXT.TabIndex = 12
    	#
    	# label4
    	#
    	$label4.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$label4.Location = New-Object System.Drawing.Point(172,41)
    	$label4.Name = "label4"
    	$label4.Size = New-Object System.Drawing.Size(100,23)
    	$label4.TabIndex = 11
    	$label4.Text = "SearchRoot "
    	#
    	# SrchRootTXT
    	#
    	$SrchRootTXT.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$SrchRootTXT.Location = New-Object System.Drawing.Point(284,39)
    	$SrchRootTXT.Name = "SrchRootTXT"
    	$SrchRootTXT.Size = New-Object System.Drawing.Size(148,20)
    	$SrchRootTXT.TabIndex = 10
    	#
    	# label2
    	#
    	$label2.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$label2.Location = New-Object System.Drawing.Point(172,14)
    	$label2.Name = "label2"
    	$label2.Size = New-Object System.Drawing.Size(100,23)
    	$label2.TabIndex = 8
    	$label2.Text = "Search Accounts"
    	#
    	# SrchAccountTxt
    	#
    	$SrchAccountTxt.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$SrchAccountTxt.Location = New-Object System.Drawing.Point(284,12)
    	$SrchAccountTxt.Name = "SrchAccountTxt"
    	$SrchAccountTxt.Size = New-Object System.Drawing.Size(148,20)
    	$SrchAccountTxt.TabIndex = 7
    	#
    	# label1
    	#
    	$label1.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$label1.Location = New-Object System.Drawing.Point(172,124)
    	$label1.Name = "label1"
    	$label1.Size = New-Object System.Drawing.Size(100,23)
    	$label1.TabIndex = 6
    	$label1.Text = "New Password"
    	#
    	# textbox1
    	#
    	$textbox1.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$textbox1.Location = New-Object System.Drawing.Point(284,124)
    	$textbox1.Name = "textbox1"
    	$textbox1.PasswordChar = '*'
    	$textbox1.Size = New-Object System.Drawing.Size(148,20)
    	$textbox1.TabIndex = 5
    	#
    	# button2
    	#
    	$button2.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$button2.Location = New-Object System.Drawing.Point(71,42)
    	$button2.Name = "button2"
    	$button2.Size = New-Object System.Drawing.Size(89,23)
    	$button2.TabIndex = 4
    	$button2.Text = "Change PWD"
    	$button2.UseVisualStyleBackColor = $True
    	$button2.add_Click($handler_button2_Click)
    	#
    	# datagridview1
    	#
    	$System_Windows_Forms_DataGridViewCellStyle_16 = New-Object System.Windows.Forms.DataGridViewCellStyle
    	$System_Windows_Forms_DataGridViewCellStyle_16.Alignment = [System.Windows.Forms.DataGridViewContentAlignment]::MiddleLeft 
    	$System_Windows_Forms_DataGridViewCellStyle_16.BackColor = [System.Drawing.Color]::FromArgb(255,240,240,240)
    	$System_Windows_Forms_DataGridViewCellStyle_16.Font = New-Object System.Drawing.Font("Microsoft Sans Serif",8.25,0,3,1)
    	$System_Windows_Forms_DataGridViewCellStyle_16.ForeColor = [System.Drawing.Color]::FromArgb(255,0,0,0)
    	$System_Windows_Forms_DataGridViewCellStyle_16.SelectionBackColor = [System.Drawing.Color]::FromArgb(255,51,153,255)
    	$System_Windows_Forms_DataGridViewCellStyle_16.SelectionForeColor = [System.Drawing.Color]::FromArgb(255,255,255,255)
    	$System_Windows_Forms_DataGridViewCellStyle_16.WrapMode = [System.Windows.Forms.DataGridViewTriState]::True 
    	$datagridview1.ColumnHeadersDefaultCellStyle = $System_Windows_Forms_DataGridViewCellStyle_16
    	$datagridview1.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$System_Windows_Forms_DataGridViewCellStyle_17 = New-Object System.Windows.Forms.DataGridViewCellStyle
    	$System_Windows_Forms_DataGridViewCellStyle_17.Alignment = [System.Windows.Forms.DataGridViewContentAlignment]::MiddleLeft 
    	$System_Windows_Forms_DataGridViewCellStyle_17.BackColor = [System.Drawing.Color]::FromArgb(255,255,255,255)
    	$System_Windows_Forms_DataGridViewCellStyle_17.Font = New-Object System.Drawing.Font("Microsoft Sans Serif",8.25,0,3,1)
    	$System_Windows_Forms_DataGridViewCellStyle_17.ForeColor = [System.Drawing.Color]::FromArgb(255,0,0,0)
    	$System_Windows_Forms_DataGridViewCellStyle_17.SelectionBackColor = [System.Drawing.Color]::FromArgb(255,51,153,255)
    	$System_Windows_Forms_DataGridViewCellStyle_17.SelectionForeColor = [System.Drawing.Color]::FromArgb(255,255,255,255)
    	$System_Windows_Forms_DataGridViewCellStyle_17.WrapMode = [System.Windows.Forms.DataGridViewTriState]::False 
    	$datagridview1.DefaultCellStyle = $System_Windows_Forms_DataGridViewCellStyle_17
    	$datagridview1.Location = New-Object System.Drawing.Point(34,165)
    	$datagridview1.Name = "datagridview1"
    	$System_Windows_Forms_DataGridViewCellStyle_18 = New-Object System.Windows.Forms.DataGridViewCellStyle
    	$System_Windows_Forms_DataGridViewCellStyle_18.Alignment = [System.Windows.Forms.DataGridViewContentAlignment]::MiddleLeft 
    	$System_Windows_Forms_DataGridViewCellStyle_18.BackColor = [System.Drawing.Color]::FromArgb(255,240,240,240)
    	$System_Windows_Forms_DataGridViewCellStyle_18.Font = New-Object System.Drawing.Font("Microsoft Sans Serif",8.25,0,3,1)
    	$System_Windows_Forms_DataGridViewCellStyle_18.ForeColor = [System.Drawing.Color]::FromArgb(255,0,0,0)
    	$System_Windows_Forms_DataGridViewCellStyle_18.SelectionBackColor = [System.Drawing.Color]::FromArgb(255,51,153,255)
    	$System_Windows_Forms_DataGridViewCellStyle_18.SelectionForeColor = [System.Drawing.Color]::FromArgb(255,255,255,255)
    	$System_Windows_Forms_DataGridViewCellStyle_18.WrapMode = [System.Windows.Forms.DataGridViewTriState]::True 
    	$datagridview1.RowHeadersDefaultCellStyle = $System_Windows_Forms_DataGridViewCellStyle_18
    	$datagridview1.Size = New-Object System.Drawing.Size(829,356)
    	$datagridview1.TabIndex = 2
    	#
    	# button1
    	#
    	$button1.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$button1.Location = New-Object System.Drawing.Point(71,12)
    	$button1.Name = "button1"
    	$button1.Size = New-Object System.Drawing.Size(89,23)
    	$button1.TabIndex = 1
    	$button1.Text = "Get Servers"
    	$button1.UseVisualStyleBackColor = $True
    	$button1.add_Click($handler_button1_Click)
    	#
    	# tooltip1
    	#
    	#endregion Generated Form Code
    
    	#----------------------------------------------
    
    	#Save the initial state of the form
    	$InitialFormWindowState = $form1.WindowState
    	#Init the OnLoad event to correct the initial state of the form
    	$form1.add_Load($Form_StateCorrection_Load)
    	#Show the Form
    	return $form1.ShowDialog()
    
    } #End Function
    
    #Call OnApplicationLoad to initialize
    if(OnApplicationLoad -eq $true)
    {
    	#Create the form
    	GenerateForm | Out-Null
    	#Perform cleanup
    	OnApplicationExit
    }
    
    

  • Scheduled Tasks Server 2008(R2)

    I have been working on a script for changing passwords on scheduled tasks in our domain, in that process I have run into a few kinks with scheduled tasks in server 2008(R2).

    I tried different ways of manipulating the scheduled tasks, but ended up using schtasks.exe from the commandline, so I wrote some Powershell code to wrap around the schtasks.exe to connect to multiple machines.. But I kept getting errors on some servers, so I decided to dig into the issue. After a lot of testing I figured out, that scheduled tasks created from the Task Scheduler GUI, could not be changed with schtasks.exe from the commandline.
    So I had to dig a little deeper, and figure out what was happening, and how to work around it. The problem can be seen if you export the scheduled task into XML.

    The first picture here is a scheduled task created from the command line.

    image

     

    This one is from a scheduled task created from the Task scheduler GUI (Notice the date format contains 6 or 7 decimals)

    image

    Apparently schtasks.exe does not like the date/time format in a task created in the GUI, but if you export the scheduled task to XML change remove the “decimals” and reimport the scheduled task, you can now manage it from the command line with schtasks.exe (How was this not caught in testing ??)

     

    So to avoid going out to all 2008(R2) machines and do it manually, I wrote a small Powershell script to dump a scheduled task to XML and change the date/time and reimport it.

     
    Function Update-ScheduledTask {
    param(
      [Parameter(Position=1,Mandatory=$true)]
      $SchedName ,
      [Parameter(Position=2,Mandatory=$false)]
      $ComputerName = "Localhost"
      )
      
    $ShortDate = [regex]"(?<ShortDate>[0-9]{4}[/.-](?:1[0-2]|0[1-9])[/.-](?:3[01]|[12][0-9]|0[1-9])T(?:2[0-3]|[01][0-9])[:.][0-5][0-9][:.][0-5][0-9])(?<Digits>\.\d*)"
    Remove-Item "$Env:TEMP\$($SchedName).xml"
    $XMLIn = schtasks /query /s $Computername /tn $SchedName /xml 
    
    foreach ($line in $XMLIn){
    If ($line -match "$ShortDate") {
    $line = [regex]::Replace($line, $ShortDate, $($Matches["Shortdate"]))
    }
    If ($line.length -gt 1) {
    $line | Out-File -Append -FilePath "$Env:TEMP\$($SchedName).xml"}
    }
    schtasks /Create /tn $SchedName /XML "$Env:TEMP\$($SchedName).xml" /f
    }
      

  • Free online Source Control with PowerGui Pro.

    Currently I am using a free plan with Dynamsoft for source control with PowerGui, you get 25 MB for free, which will last me a long time at my current speed of writing PowerShell scripts Smile

     

    Here is a quick guide to setting up an account.

    Go to http://www.dynamsoft.com/products/SAWHosted_FreePlan.aspx and sign up for a free account.

    Just fill in your information, and wait for the confirmation email. When the mail arrives you have to click the link to activate your account, on that page there is a link to download the Dynamsoft Source AnyWhere Hosted Server Manager:

    http://www.dynamsoft.com/downloads/sawhosted_download.aspx

    I my case running on Windows I choose the Windows version Smile

     

    image

    Download and install the client.

    It prompts you if you want to make it your default Source Control provider, which in my case I choose yes, since this is my private machine.

    SNAGHTML562d4a8

     

    You then fire you PowerGui Pro, and go to Tools –> Options

    image

    Under options you choose  “Version Control” and in Current provider you choose Dynamsoft SourceAnyware Hosted then click advanced.

    SNAGHTML5665897

    In the General Pane I choose a new path for saving Temp files.

    SNAGHTML5687a49

    Under External Programs I put in the path for PowerGUI Pro, in my Case: C:\Program Files (x86)\Quest Software\PowerGUI Pro\ScriptEditor.exe

    (I use WinMerge for file comparison, so that is what you see in the image below WinMerge can be downloaded here: http://winmerge.org/ )

    SNAGHTML56e1b87

    If you do not want to view the DynamSoft Login log every time you login.

    SNAGHTML573002b

    First time you try to save a script in PowerGui Pro, it will prompt you if you want to check it into your Source Control system.

    A login box will appear, fill in the fields with the data from your welcome mail, and choose if you want to be prompted for a password, everything you check something in/out.

    SNAGHTML57787e1

    You get prompted to choose a Repository, in this case just choose “default”

    SNAGHTML57a1a7e

    In my case I have a few existing Projects, but I choose to create a new Project called “Test Project”

    SNAGHTML57b4852SNAGHTML589f256

    You then get prompted to put in a comment

    SNAGHTML58aa56f

    In PowerGui you now have an extra menu called “Version Control” and you can see a mark on each tab if your script is in the source control and if it is checked in or out.

    image (The arrow on the tab is blue if the script is checked in, and red if it is checked out)

    I have checked the script out (If you try to edit the script, it will automatically prompt you to check out the script), I made some changes, and try to check it in again.

    image

    image

    You get prompted to enter a comment, after that is entered the file is checked back in.. (You can leave to comment field blank if you do not want to write something)

    SNAGHTML590ed57

    You can manage your software projects from the DynamSoft application.

    Go to start menu and choose Dynamsoft SourceAnywhere Hosted

    Sign in with your username/Password

     

    First thing do to is go to Tools –> Options –> External Programs

     

    SNAGHTML5bbb316

    As you can see my test project is now in my list of projects.

    image

    One thing I have noticed is that Dynamsoft default checks files in as Binary files, which means it does not allow you to do a text comparison of the two, in order to change that  right click the .ps1 file and choose properties.

    image

    Then you change the type from Binary to Mergeable, you can now compare your different versions of checked in files.

    SNAGHTML5a0136e

     

    Right click the file you want to “compare”, then choose  “Show History”, you get a lot of options to choose from, in most cases the default options are enough. Click OK

     

    In this example I have made an initial version of the script then made some changes and checked it back in.

    I highlight both files and choose Diff

    SNAGHTML5a42317

    This will bring up WinMerge and show the differences (This is a horrible example of file comparison I Know)

     

    image

     

    This guide should be enough to get you started…  Smile

     

    Edit:

     

    Here is a better example of script a script comparison.

    SNAGHTML5a9248d

    image


  • 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.

    $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
    

    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.

    $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
    

    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.

    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
           }
    }
     
    
    

    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.

    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
        }
    }
    

    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.

    
    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
    

  • Account lockout continued

    I considered putting this in the script I wrote for checking Services/Scheduled Tasks/COM+ objects, but it just gave me too much output, so I decided to put this in a separate script, and tried to put a GUI around it, since it has been a while since I have opened Primal Forms.

    The script takes a username, it then connects to all servers in your domain, and checks to see if the username you typed in has a connection to that server, it does so by querying Win32_LoggedOnUser (You will be surprised by how many connections you have to different machines)

    The script requires Powershell V2, Quest AD cmdlets.

    ########################################################################
    # Code Generated By: SAPIEN Technologies, Inc., PrimalForms 2009 v1.1.9.0
    # Generated On: 08-09-2010 22:12
    # Generated By: CTN
    ########################################################################
    
    #----------------------------------------------
    #region Application Functions
    #----------------------------------------------
    
    function OnApplicationLoad {
    	#Note: This function runs before the form is created
    	#Note: To get the script directory in the Packager use: Split-Path $hostinvocation.MyCommand.path
    	#Note: To get the console output in the Packager (Windows Mode) use: $ConsoleOutput (Type: System.Collections.ArrayList)
    	#Important: Form controls cannot be accessed in this function
    	#TODO: Add snapins and custom code to validate the application load
    	
    	return $true #return true for success or false for failure
    }
    
    function OnApplicationExit {
    	#Note: This function runs after the form is closed
    	#TODO: Add custom code to clean up and unload snapins when the application exits
    	
    	$script:ExitCode = 0 #Set the exit code for the Packager
    }
    
    #endregion
    
    #----------------------------------------------
    # Generated Form Function
    #----------------------------------------------
    function GenerateForm {
    
    	#----------------------------------------------
    	#region Import Assemblies
    	#----------------------------------------------
    	[void][reflection.assembly]::Load("System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
    	[void][reflection.assembly]::Load("System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
    	[void][reflection.assembly]::Load("mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
    	[void][reflection.assembly]::Load("System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
    	#endregion
    	
    	#----------------------------------------------
    	#region Generated Form Objects
    	#----------------------------------------------
    	[System.Windows.Forms.Application]::EnableVisualStyles()
    	$form1 = New-Object System.Windows.Forms.Form
    	$label5 = New-Object System.Windows.Forms.Label
    	$label4 = New-Object System.Windows.Forms.Label
    	$label3 = New-Object System.Windows.Forms.Label
    	$label2 = New-Object System.Windows.Forms.Label
    	$label1 = New-Object System.Windows.Forms.Label
    	$progressbar1 = New-Object System.Windows.Forms.ProgressBar
    	$listbox1 = New-Object System.Windows.Forms.ListBox
    	$CheckBTN = New-Object System.Windows.Forms.Button
    	$Usernametxt = New-Object System.Windows.Forms.TextBox
    	$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
    	#endregion Generated Form Objects
    
    	#----------------------------------------------
    	# User Generated Script
    	#----------------------------------------------
    
    	
    	
    	
    	
    	$FormEvent_Load={
    		#TODO: Initialize Form Controls here
    		
    	}
    	
    	$handler_textbox1_TextChanged={
    	#TODO: Place custom script here
    	
    	}
    	
    	$handler_CheckBTN_Click={
    	
    	#TODO: Place custom script here
    	$i = 1
    	$ErrorActionPreference ="silentlycontinue"
    	 $Servers = get-QADComputer -SearchRoot 'appension.local/' -OSName "*Server*"
    	 
    	 $progressbar1.Maximum(($Servers).length)
    	 $label2.Text = $servers.length
    	 
    	 Foreach ($server in $Servers) {
    	 $users = get-WmiObject -computer $server.Name Win32_LoggedOnUser | select Antecedent -Unique
    	 $label4.Text = $i
    	 $i++
    	 $label5.Text = $Server.name
    	  $progressbar1.Increment("1")
    	 
    	 Foreach ($user in $users) {
    	
    	
    	$domainname =([regex]::Match($user.Antecedent, 'Domain="(?<domain>.*?)"')).Groups["domain"].Value 
    	$username = ([regex]::Match($user.Antecedent, 'Name="(?<name>.*?)"')).Groups["name"].Value
    	If ($username -like $Usernametxt.Text) {
    	#Write-Host "*************   $($server.name) ********************"
    	$listbox1.Items.Add($Servers.name)
    	 }
    	 }
    	 }
    	}
    	
    	$handler_label1_Click={
    	#TODO: Place custom script here
    	
    	}
    	
    	$handler_listbox1_SelectedIndexChanged={
    	#TODO: Place custom script here
    	
    	}
    	
    	#----------------------------------------------
    	# Generated Events
    	#----------------------------------------------
    	
    	$Form_StateCorrection_Load=
    	{
    		#Correct the initial state of the form to prevent the .Net maximized form issue
    		$form1.WindowState = $InitialFormWindowState
    	}
    	
    	#----------------------------------------------
    	#region Generated Form Code
    	#----------------------------------------------
    	#
    	# form1
    	#
    	$form1.Controls.Add($label5)
    	$form1.Controls.Add($label4)
    	$form1.Controls.Add($label3)
    	$form1.Controls.Add($label2)
    	$form1.Controls.Add($label1)
    	$form1.Controls.Add($progressbar1)
    	$form1.Controls.Add($listbox1)
    	$form1.Controls.Add($CheckBTN)
    	$form1.Controls.Add($Usernametxt)
    	$form1.Text = "Check where user is logged in."
    	$form1.Name = "form1"
    	$form1.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$form1.ClientSize = New-Object System.Drawing.Size(418,358)
    	$form1.add_Load($FormEvent_Load)
    	#
    	# label5
    	#
    	$label5.TabIndex = 8
    	$label5.Size = New-Object System.Drawing.Size(149,18)
    	$label5.Location = New-Object System.Drawing.Point(142,302)
    	$label5.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$label5.Name = "label5"
    	#
    	# label4
    	#
    	$label4.TabIndex = 7
    	$label4.Size = New-Object System.Drawing.Size(31,18)
    	$label4.Location = New-Object System.Drawing.Point(61,303)
    	$label4.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$label4.Name = "label4"
    	#
    	# label3
    	#
    	$label3.TabIndex = 6
    	$label3.Size = New-Object System.Drawing.Size(27,18)
    	$label3.Text = "   of"
    	$label3.Location = New-Object System.Drawing.Point(84,303)
    	$label3.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$label3.Name = "label3"
    	#
    	# label2
    	#
    	$label2.TabIndex = 5
    	$label2.Size = New-Object System.Drawing.Size(33,18)
    	$label2.Location = New-Object System.Drawing.Point(109,303)
    	$label2.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$label2.Name = "label2"
    	#
    	# label1
    	#
    	$label1.TabIndex = 4
    	$label1.Size = New-Object System.Drawing.Size(42,18)
    	$label1.Text = "Server"
    	$label1.Location = New-Object System.Drawing.Point(24,303)
    	$label1.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$label1.Name = "label1"
    	$label1.add_Click($handler_label1_Click)
    	#
    	# progressbar1
    	#
    	$progressbar1.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$progressbar1.Size = New-Object System.Drawing.Size(382,23)
    	$progressbar1.TabIndex = 3
    	$progressbar1.Location = New-Object System.Drawing.Point(24,323)
    	$progressbar1.Name = "progressbar1"
    	#
    	# listbox1
    	#
    	$listbox1.FormattingEnabled = $True
    	$listbox1.Size = New-Object System.Drawing.Size(201,225)
    	$listbox1.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$listbox1.Name = "listbox1"
    	$listbox1.Location = New-Object System.Drawing.Point(24,75)
    	$listbox1.TabIndex = 2
    	$listbox1.add_SelectedIndexChanged($handler_listbox1_SelectedIndexChanged)
    	#
    	# CheckBTN
    	#
    	$CheckBTN.TabIndex = 1
    	$CheckBTN.Name = "CheckBTN"
    	$CheckBTN.Size = New-Object System.Drawing.Size(75,23)
    	$CheckBTN.UseVisualStyleBackColor = $True
    	$CheckBTN.Text = "Check"
    	$CheckBTN.Location = New-Object System.Drawing.Point(150,20)
    	$CheckBTN.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$CheckBTN.add_Click($handler_CheckBTN_Click)
    	#
    	# Usernametxt
    	#
    	$Usernametxt.Size = New-Object System.Drawing.Size(100,20)
    	$Usernametxt.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
    	$Usernametxt.Text = "Username"
    	$Usernametxt.Name = "Usernametxt"
    	$Usernametxt.Location = New-Object System.Drawing.Point(24,24)
    	$Usernametxt.TabIndex = 0
    	$Usernametxt.add_TextChanged($handler_textbox1_TextChanged)
    	#endregion Generated Form Code
    
    	#----------------------------------------------
    
    	#Save the initial state of the form
    	$InitialFormWindowState = $form1.WindowState
    	#Init the OnLoad event to correct the initial state of the form
    	$form1.add_Load($Form_StateCorrection_Load)
    	#Show the Form
    	return $form1.ShowDialog()
    
    } #End Function
    
    #Call OnApplicationLoad to initialize
    if(OnApplicationLoad -eq $true)
    {
    	#Create the form
    	GenerateForm | Out-Null
    	#Perform cleanup
    	OnApplicationExit
    }
    

  • 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.

    #==========================================================================
    # 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()
    

  • 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