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
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
}
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()
This looks very promising, going to give it a spin tomorrow when I get to work
http://www.lucd.info/2010/05/29/beyond-export-csv-export-xls/
Example #1
List users that expires within X days
$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
Example #2
Locate that Hyper-V Host
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}
Example #3
Create test users and OU’s in AD
#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
}
Example #4
Rename Groups in AD
Get-QADGroup -Name "xyz*" | %{Set-QADGroup -Identity $_ -SamAccountName ($_.Name).Replace("xyz","abc") -whatif ;Rename-QADObject -Identity $_ -NewName ($_.Name).Replace("xyz","abc") -WhatIf }
Example #5
Output a list of servers in a Excel documents, with ping stats and if the machine is disabled/enabled
#$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()
}
Example #1 (From Lee Holmes’ Powershell cookbook)
“Compile C# code on the fly”
$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
Example #2 (From Lee Holmes’ Powershell cookbook)
Showing how static functions are available directly
$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)
Example #3
Access .Net function to move mouse, in order to prevent screensaver from kicking in.
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)
}
}
Here are some of the scripts that I used during the demonstration in VA Beach.
Profiles:
Example #1
function prompt
{
"Xenophane " + $(get-location) + ">"
}
Example #2
function prompt
{
"Processes " + (Get-Process).Count+ " " + $(get-location) + "> "
}
Example #3 (Example taken from website)
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
}
Example #4 (Overdone one)
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.
}
I was asked to update my MSTSC util, so here goes.. It will now check for the configuration file and display a message if it is not there, instead of just erroring out.
I have tested it to work on Windows 7
Here is the source code:
#Include <constants .au3>
Opt("TrayOnEventMode",1)
Opt("TrayAutoPause",0)
Opt("TrayMenuMode",1) ; Default tray menu items (Script Paused/Exit) will not be shown.
Global $server[100][3]
$Console = TrayCreateMenu("Console Connect")
$Regular = TrayCreateMenu("Regular Connect")
If FileExists("servers.ini") Then
$data = IniReadSection ( @ScriptDir&"\servers.ini", "servers" )
Else
MsgBox(4096,"No Ini File found","I could not find the servers.ini file, Exiting")
Exit
EndIf
;~ For $i = 1 To $data[0][0]
;~ MsgBox(4096, "", "Key: " & $data[$i][2] & @CRLF & "Value: " & $data[$i][1])
;~ Next
$server[0][0] = $data[0][0]
For $i = 1 to $data[0][0]
$server[$i][0] = TrayCreateItem($data[$i][0], $Console)
TrayItemSetOnEvent(-1, "ServerConsole")
$server[$i][1] = TrayCreateItem($data[$i][0], $Regular)
TrayItemSetOnEvent(-1, "ServerRegular")
$server[$i][2] = $data[$i][1]
Next
TrayCreateItem("")
TrayCreateItem("About")
TrayItemSetOnEvent(-1, "DoAbout")
TrayCreateItem("")
TrayCreateItem("Exit")
TrayItemSetOnEvent(-1, "DoExit")
TraySetState()
While 1
Sleep(100)
WEnd
Func DoAbout()
Msgbox(64,"About:","Tool by Claus T. Nielsen")
EndFunc
Func DoExit()
Exit
EndFunc
Func ServerConsole()
For $i = 1 to $server[0][0]
If $server[$i][0] = @TRAY_ID Then
Run("mstsc -v:"&$server[$i][2]&" /F -admin")
ExitLoop
EndIf
Next
EndFunc
Func ServerRegular()
For $i = 1 to $server[0][0]
If $server[$i][1] = @TRAY_ID Then
Run("mstsc -v:"&$server[$i][2]&" ")
ExitLoop
EndIf
Next
EndFunc
Here is an example on the servers.ini file.
;Server.ini example ; Right side of the Equal sign is the server name/address, ; left side is the name you want displayed ;This files has to be located in the same dir as the .exe file. [Servers] ServerTest 10.0.0.1 = ServerTest ExchangeServer = 10.0.0.2 Fileserver01 = Fileserver01.domain.com
For those of you who trust me, here are two precompiled editions:
64 Bit
32 Bit
EDIT
Sorry about that folks, seems as if there was some trouble with the HTML formatting, some of the quotes had been replaced with “AMP;”, this should be fixed now.
Today Windows Management Framework was released in its final version for Windows XP, and Server 2003, Windows Vista and Server 2008. Windows Management Framework contains Powershell v2, WinRM 2.0 and BITS 4.0.
A question was posted on a forum today, on how to find out how many active sessions was on a Server 2008 Terminal Server, the poster said that on his 2003 Terminal Server he could query the WMI class Win32_PerfFormattedData_TermService_TerminalServices, but that did not work on Server 2008.
So I thought I would give it a shot and see if I could find it, I assumed that it was replaced by a new class, so I had to search the different WMI classes to find the new one.
# Find WMI TS Class
#CTN
Get-WMIObject -ComputerName "TSServer" -List *term* | % {($_.Properties | where {$_.Name -like "*session*"}) } | ft name, Origin
What I do here is tell Get-Wmiobject to list all wmi classes on server “TSServer” that contains the word “term” (I guessed it would be called something with terminal services still)
The foreach of the classes returned I check if it has a property that contains the word “session”, and just output that as a table, resulting in this on a Server 2008 R2 running Remote Desktop Services.
Name Origin
—- ——
DisconnectedSessions Win32_TerminalService
TotalSessions Win32_TerminalService
ActiveSessions Win32_PerfFormattedData_LocalSessionManager_TerminalServices
InactiveSessions Win32_PerfFormattedData_LocalSessionManager_TerminalServices
TotalSessions Win32_PerfFormattedData_LocalSessionManager_TerminalServices
ActiveSessions Win32_PerfRawData_LocalSessionManager_TerminalServices
InactiveSessions Win32_PerfRawData_LocalSessionManager_TerminalServices
TotalSessions Win32_PerfRawData_LocalSessionManager_TerminalServices
Of course to be able to do this, I had to know/guess that the class contained “term” and that the property would be named something with “session”

Categories
Tag Cloud
Blog RSS
Comments RSS
Last 50 Posts
Back
Void « Default
Life
Earth
Wind
Water
Fire
Light 