I have written a ps script which do the the job when i execute it from ISE but when i save it and run it from CMD i have an error,
basicly i have made gui with list of OU and list of GPO and i wanted to make a link and unlink button (eg OU named blabla and GPO named GPOblabla so if i check them both and press link the code would link and unlink would unlink)
the problem is (with my understanding) with the button2 (unlink) function which is defined at the beginning of the code, and in that function im using command that use parameters later in the code, i guess ISE save it in memory? whats the best thing to do here?
here is the code:
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$button2_click = {
try {Remove-GPLink -Name $GPO -target $OU}
catch {
Write-Warning $Error[0]
} $form.close() }
$form = New-Object System.Windows.Forms.Form
$form.Text = 'GPO Connector V1.0'
$form.Size = New-Object System.Drawing.Size(600,200)
$form.StartPosition = 'CenterScreen'
$button1 = New-Object System.Windows.Forms.Button
$button1.Location = New-Object System.Drawing.Point(10,120)
$button1.Size = New-Object System.Drawing.Size(75,23)
$button1.Text = 'Link'
$button1.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $button1
$button2 = New-Object System.Windows.Forms.Button
$button2.Location = New-Object System.Drawing.Point(90,120)
$button2.Size = New-Object System.Drawing.Size(75,23)
$button2.Text = 'UnLink'
$Button2.Add_Click($Button2_Click)
$label = New-Object System.Windows.Forms.Label
$label.Location = New-Object System.Drawing.Point(80,20)
$label.Size = New-Object System.Drawing.Size(480,20)
$label.Text = 'SELECT GPO And Corresponding OU (ONLY WORKSTATION OU)'
$form.Controls.Add($label)
$form.Controls.Add($button1)
$form.Controls.Add($button2)
$listBox = New-Object System.Windows.Forms.ListBox
$listBox.Location = New-Object System.Drawing.Point(10,40)
$listBox.Size = New-Object System.Drawing.Size(260,20)
$listBox.Height = 80
$listBox2 = New-Object System.Windows.Forms.ListBox
$listBox2.Location = New-Object System.Drawing.Point(300,40)
$listBox2.Size = New-Object System.Drawing.Size(260,20)
$listBox2.Height = 80
#gpolist.txt holding the gpo's and oulist.txt would hold the ou's
Get-Content .\gpolist.txt | ?{$_ -notmatch "^#"} | Where-Object { $_.Trim() -ne '' } | ForEach-Object {
[void] $listBox.Items.Add("$_")}
Get-Content .\oulist.txt | ?{$_ -notmatch "^#"} | Where-Object { $_.Trim() -ne '' } | ForEach-Object {
[void] $listBox2.Items.Add("$_")}
$form.Controls.Add($listBox)
$form.Controls.Add($listBox2)
$form.Topmost = $true
$result = $form.ShowDialog()
if ($result -eq [System.Windows.Forms.DialogResult]::Cancel)
{ break }
if ($result -eq [System.Windows.Forms.DialogResult]::OK)
{
$GPO = $listBox.SelectedItem
$OU = $listBox2.SelectedItem }
New-GPLink $GPO -target $OU | out-null }
You're not setting variables $GPO and $OU until after showing the dialog, so these variables won't be defined in your $button2_click script block, so the Remove-GPLink call won't work as expected.
One way to solve the problem is to refer to both $listBox.SelectedItem and $listBox2.SelectedItem directly:
$button2_click = {
try {
Remove-GPLink -Name $listBox.SelectedItem -target $listBox2.SelectedItem
}
catch {
Write-Warning $Error[0]
}
$form.close()
}
Note that if you were to define variables $GPO and $OU inside that script block, you'd have to define them as $script:GPO = ... and script:$OU = ... if you wanted to also access them after closing the dialog.
As for why things worked in the ISE:
The ISE dot-sources your scripts when it runs them, and with repeated invocations variables may linger and affect subsequent runs.
The implication is that you had run at least once with the code path $GPO = $listBox.SelectedItem and $OU = $listBox2.SelectedItem getting hit, which would have made clicking on button 2 in subsequent runs "work".
Related
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
$form = New-Object System.Windows.Forms.Form
$form.Size = New-Object System.Drawing.Size(500,300)
$form.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen
$label = New-Object System.Windows.Forms.Label
$label.Text = "Click the button to view the ProfileList registry in regedit"
$label.Size = New-Object System.Drawing.Size(300,30)
$label.Location = New-Object System.Drawing.Point(100,50)
$display_button = New-Object System.Windows.Forms.Button
$display_button.Text = "Display ProfileList"
$display_button.Size = New-Object System.Drawing.Size(150,30)
$display_button.Location = New-Object System.Drawing.Point(175,100)
$display_button.Add_Click({
regedit "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList"
})
$form.Controls.Add($label)
$form.Controls.Add($display_button)
$form.ShowDialog()
Upon running the script I receive the following error:
"Error opening the file"
I am not sure if the path is correct, can someone point out what I'm doing wrong?
Before opening regedit.exe, perform the following:
Set-ItemProperty 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Applets\Regedit' 'LastKey' 'Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList'
or
$splat = #{
'Path' = 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Applets\Regedit'
'Name' = 'LastKey'
'Value' = 'Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList'
}
Set-ItemProperty #splat
and edit your button click actdion to simply:
$display_button.Add_Click({
regedit
})
I'm using this code in 2012 server but unable to run in windows 2008, i'm new to powershell script which tried to search online but unable to find an answer.
The error come from -property, which i tried -properties and pipe before -property also can't.
$OS = Get-WmiObject Win32_OperatingSystem | Select-Object Caption,Version,ServicePackMajorVersion,OSArchitecture,CSName,WindowsDirectory
$HostName = [System.Net.Dns]::GetHostName()
$TargetPath = Get-Location
$ExportPath = $TargetPath.Path + "\" + $HostName + "_" + $OS.Caption + ".csv"
$UserAccount = Get-WmiObject -Class Win32_UserAccount -Filter "LocalAccount='True'"
$NetworkLoginProfile = Get-WmiObject -Class Win32_NetworkLoginProfile
$GroupUser = Get-WmiObject -Class Win32_GroupUser
if (Test-Path $ExportPath)
{
Remove-Item $ExportPath
}
Foreach($Account in $UserAccount){
$Description = $Account.Description
$Description = $Description.replace("`r`n","_")
$Description = $Description.TrimEnd()
$Profile = #{
HostName = $HostName
Domain = $Account.Domain
LocalAccount = $Account.LocalAccount
SID = $Account.SID
Name = $Account.Name
Caption = $Account.Caption
Status = $Account.Status
Disabled = $Account.Disabled
Lockout = $Account.Lockout
FullName = $Account.FullName
Description = $Description
AccountType = $Account.AccountType
PasswordRequired = $Account.PasswordRequired
PasswordExpires = $Account.PasswordExpires
PasswordChangeable = $Account.PasswordChangeable
NumberOfLogons = ""
LastLogon = ""
UserComment = ""
UserId = ""
UserType = ""
Workstations = ""
BadPasswordCount = ""
GroupMemberShip = ""
}
Foreach ($NetworkProfile in $NetworkLoginProfile)
{
If ($Account.Caption -eq $NetworkProfile.Name)
{
$Profile.NumberOfLogons = $NetworkProfile.NumberOfLogons
$Profile.LastLogon = $NetworkProfile.LastLogon
$Profile.UserComment = $NetworkProfile.UserComment
$Profile.UserID = $NetworkProfile.UserId
$Profile.UserType = $NetworkProfile.UserType
$Profile.Workstations = $NetworkProfile.Workstations
$Profile.BadPasswordCount = $NetworkProfile.BadPasswordCount
}
}
$Groups = New-Object System.Collections.ArrayList
Foreach ($User in $GroupUser)
{
$PartComponent = $User.PartComponent
$Index1 = $PartComponent.indexOf("Name=")
$MemberName = $PartComponent.substring($Index1)
$MemberName = $MemberName.substring(6)
$MemberName = $MemberName.subString(0, $MemberName.indexOf("`""))
$Index2 = $PartComponent.indexOf("Domain=")
$MemberDomain = $PartComponent.subString($Index2)
$MemberDomain = $MemberDomain.substring(8)
$MemberDomain = $MemberDomain.substring(0, $MemberDomain.indexOf("`""))
if (($MemberDomain -eq $Account.Domain) -and ($MemberName -eq $Account.Name))
{
$GroupComponent = $User.GroupComponent
$Index3 = $GroupComponent.indexOf("Name=")
$MemberGroup = $GroupComponent.substring($Index3)
$MemberGroup = $MemberGroup.substring(6)
$MemberGroup = $MemberGroup.subString(0, $MemberGroup.indexOf("`""))
if($MemberGroup)
{
$Groups.Add($MemberGroup)
}
}
}
$count = 0
Foreach ($Group in $Groups)
{
$count++
if($count -lt $Groups.Count){
$Profile.GroupMemberShip += $Group + '|'
}
else{
$Profile.GroupMemberShip += $Group
}
}
$Csv = New-Object psobject -Property $Profile
$Csv | Select-Object -Property Hostname,Domain,LocalAccount,SID,Name,Caption,Status,Disabled,Lockout,FullName,Description,AccountType,PasswordRequired,PasswordExpires,PasswordChangeable,NumberOfLogons,LastLogon,UserComment,UserId,UserType,Workstations,BadPasswordCount,GroupMemberShip | Export-Csv $ExportPath -Append -Delimiter ',' -NoTypeInformation
}
Error I receive:
Since it's no longer supported, it's tough to find documentation this far back, but I found mention of New-Object -Property being used in Windows Powershell 2.0. In the comments under your question, you state that you are running Powershell 1.0. I am fairly confident that -Property did not exist on New-Object in v1.0, so you likely need to update your Windows Management Framework to get Powershell 2.0 or later.
Note that 2.0 is no longer supported so I would recommend going with a more recent verison of Windows Powershell, at least 4.0 if not 5.1. If you can, Powershell Core (v6) would give you the most modern Powershell experience, and will work with most Windows Powershell cmdlets on Windows systems if you install the WindowsCompatibility PowerShell module.
I'm using Windows 10 Enterprise 1709 and PowerShell ISE v5. I am trying to get the last write time to the file deployment.properties by checking to see if the testpath holds the file and if it does, write the LastWriteTime of that file. I'm not sure I'm doing this the correct way. Any help showing me how to make this work would be appreciated. I've tried several options but this is the only one that doesn't produce an error. However, the code runs, completes without error but doesn't produce and output. My code is listed below first and then the output I see on the PowerShell ISE screen.
Set-ExecutionPolicy Bypass
$env:COMPUTERNAME = HostName
$DeplPath = "AppData\LocalLow\Sun\Java\Deployment\deployment.properties"
$dateTime = foreach ($User in Get-ChildItem C:\Users -Directory) {
$folderFile = Join-Path $javauser.FullName $DeplPath
if (Test-Path $folderFile) {
$testResult = Get-ChildItem | select -Property fullName, LastWriteTime
} Else {
$testResult = "Not found - deployment.properties"
}
}
$dateTime
Below is the output I get which returns no information.
PS C:\WINDOWS\system32> Set-ExecutionPolicy Bypass
$env:COMPUTERNAME = HostName
$DeplPath = "AppData\LocalLow\Sun\Java\Deployment\deployment.properties"
$dateTime = foreach ($User in Get-ChildItem C:\Users -Directory) {
$filelist = Join-Path $User.FullName $file
if (Test-Path $filelist) {
$testResult = Get-ChildItem $dateTime | select -Property fullName, LastWriteTime
} Else {
$testResult = "Not found - deployment.properties"
}
}
$dateTime
PS C:\WINDOWS\system32>
Newly modified code below
Set-ExecutionPolicy Bypass
$env:COMPUTERNAME = HostName
$DeplPath = "AppData\LocalLow\Sun\Java\Deployment\deployment.properties"
$dateTime = foreach ($User in Get-ChildItem C:\Users -Directory) {
$folderFile = Join-Path $User.FullName $DeplPath
if (Test-Path $folderFile) {
$testResult = Get-ChildItem | select -Property fullName, $DeplPath.LastWriteTime
} Else {
$testResult = "Not found - deployment.properties"
}
[PSCustomObject]#{
"Computer Name" = $env:COMPUTERNAME
"Java User True/False" = $TestResult
"Users" = $user.Name
"Last Write Time" = $testResult.LastWriteTime
}
}
$dateTime
Try this out. Your property select for the get-childitem were mislabeled.
Set-ExecutionPolicy Bypass
$env:COMPUTERNAME = HostName
$DeplPath = "AppData\LocalLow\Sun\Java\Deployment\deployment.properties"
$dateTime = foreach ($User in Get-ChildItem C:\Users -Directory) {
$folderFile = Join-Path $User.FullName $DeplPath
$test = Test-Path $folderFile
if ($test -eq $True) {
$testResult = Get-ChildItem $folderfile | select -Property Name, LastWriteTime
} Else {
$testResult = "Not found - deployment.properties"
}
[PSCustomObject]#{
"Computer Name" = $env:COMPUTERNAME
"Java User True/False" = $TestResult
"Users" = $user.Name
"Last Write Time" = $testResult.LastWriteTime
}
}
$dateTime
I'm having trouble clearing a listbox that I created in my PowerShell form. If I call the listbox.Item.Clear method, the data stored in the listbox object is cleared but the items displayed in the from remain. Even after I try to create a new, blank listbox, the old items are still displayed. The listbox is created in a function that is called by a button click. I want the listbox to be cleared and repopulated each time the button is clicked. I can easily clear and re-add text to a text box by doing something like $textbox.Text = "new text". Is there a way to do this with a listbox? Here's what I have:
function AddMembers() {
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$form = New-Object System.Windows.Forms.Form
$form.Text = 'Select a Computer'
$form.Size = New-Object System.Drawing.Size(610,450)
$form.StartPosition = 'CenterScreen'
# Create the TextBox used to capture the user's text.
$textBox = New-Object System.Windows.Forms.Textbox
$textBox.Location = '10,40'
$textBox.Size = '375,170'
$textBox.AcceptsReturn = $true
$textBox.Multiline = $true
#$textBox.Text = $UserInputData
$form.Controls.Add($textBox)
function Global:GetTheSearchString() {
# If any text is present in the text box, convert it to a sting, parse, then conver to array $Global:UserInput2
$UserInput = $textBox.ToString()
$UserInput = $UserInput -replace "System.Windows.Forms.TextBox, Text: "
$Global:UserInput2 = $UserInput -split "`r`n"
Write-Host $Global:UserInput2
$InputLength = $UserInput2.Length
Write-Host $InputLength
$Global:lastLine = $UserInput2[$InputLength -1]
Write-Host "$Global:lastLine lastLine"
#return $Global:lastLine
}
# Take an input string, search AD, and return the results as an array.
function Global:SearchAD($SearchString) {
$Groups = Get-ADObject -LDAPFilter "(cn=$SearchString*)" | select Name | Out-String
$Groups = $Groups -replace "Name"
$Groups = $Groups -replace "----"
$Groups = $Groups.Trim()
$GroupsArray = $Groups -split "`r`n"
#Write-Host $GroupsArray
return $GroupsArray
}
# Create the list box for displaying search results
function CreateListBoxResults($searchResults, $param) {
$listBox = New-Object System.Windows.Forms.ListBox
#$form.Controls.Add($listBox)
#$listBox.Items.Clear()
#$listBox = New-Object System.Windows.Forms.ListBox
$listBox.Location = New-Object System.Drawing.Point(10,225)
$listBox.Size = New-Object System.Drawing.Size(375,20)
$listBox.Height = 150
# Add values to the list box
foreach ($line in $searchResults) {
[void] $listBox.Items.Add($line)
Write-Host $line
}
#$listBox.Refresh()
$form.Controls.Add($listBox)
Write-Host "$param param"
#Write-Host "$listBox listbox"
$form.Controls.Add($listBox)
if ($param -eq $true) {
Write-Host "$param param"
$listBox.Dispose()
$listBox.Items.Clear()
$form.Controls.Add($listBox)
}
}
#$selectButton.Add_Click({ [string]$selection = $listBox.SelectedItem.ToString(); Write-Host $selection; Global:ResetSearchBox($selection)})
#$selectButton.Add_Click({ Write-Host $Global:listBox; $click = $true; $Global:listBox.Items.Clear(); $form.Controls.Remove($Global:listBox); $form.Controls.Add($Global:listBox)})
Write-Host $UserInput2
$checkButton = New-Object System.Windows.Forms.Button
$checkButton.Location = New-Object System.Drawing.Point(9,380)
$checkButton.Size = New-Object System.Drawing.Size(85,23)
$checkButton.Text = 'Check Name'
$form.Controls.Add($checkButton)
$checkButton.Add_Click({ Global:GetTheSearchString; Write-Host "$Global:lastLine check"; CreateListBoxResults (Global:SearchAD($Global:lastLine)) $false })
$selectButton = New-Object System.Windows.Forms.Button
$selectButton.Location = New-Object System.Drawing.Point(102,380)
$selectButton.Size = New-Object System.Drawing.Size(75,23)
$selectButton.Text = 'Select'
$form.Controls.Add($selectButton)
$selectButton.Add_Click({ CreateListBoxResults $nul $true})
#$form.Controls.Add($listBox)
$form.Topmost = $true
$form.Add_Shown({$form.Activate()})
$form.ShowDialog() > $nul
}
AddMembers
For clearing the listbox you are right in using listbox.Item.Clear().
However there are some other usefull methods:
$listBox.Dispose()
The Dispose method leaves the Component in an unusable state. (You might not want this one.)
$form.Controls.Remove($listBox)
Remove your listbox from the form instead of deleting the object.
$listBox.Visible = $false (or $true)
Hide your listbox instead of removing it
$listBox.Items.Clear()
$listBox.Items.AddRange(*SomeArrayHere*)
The closest you can get to $textbox.text = "NewText"
Using some of these your function could look something like this:
function CreateListBoxResults($searchResults, $param) {
# Only create a listbox if it doesn't exist
if (!$listBox) {
$listBox = New-Object System.Windows.Forms.ListBox
$listBox.Location = New-Object System.Drawing.Point(10,225)
$listBox.Size = New-Object System.Drawing.Size(375,20)
$listBox.Height = 150
}
# Add listbox to form
$form.Controls.Add($listBox)
# Add values to the list box
$listBox.Items.Clear()
foreach ($line in $searchResults) {
[void] $listBox.Items.Add($line)
Write-Host $line
}
# Remove listbox from form if $param = $true
Write-Host "$param param"
if ($param -eq $true) {
Write-Host "$param param"
$form.Controls.Remove($listBox)
}
}
I have a list of users in a CSV File that I want to find out if/when they last logged in. I can get this info for an individual account but I need to write this to a file for several accounts.
The error I'm getting:
At line:5 char:7
import-module activedirectory
Missing = operator after key in hash literal
hash literal was incomplete
My Code:
$resultList = #()
Import-Csv C:\Users\admin\Desktop\SamAccountName.csv -header("SamAccountName") | Foreach-Object{
$user = ([adsisearcher]"(samAccountName=$($_.SamAccountName))").FindOne()
$resultList += New-Object -TypeName PSObject -Property #{
SamAccountName = $_.SamAccountName
Import-Module ActiveDirectory
function Get-ADUserLastLogon([string]$_.userName)
{
$dcs = Get-ADDomainController -Filter {Name -like "*"}
$time = 0
foreach($dc in $dcs)
{
$hostname = $dc.HostName
$user = Get-ADUser $userName | Get-ADObject -Properties lastLogon
if($user.LastLogon -gt $time)
{
$time = $user.LastLogon
}
}
$dt = [DateTime]::FromFileTime($time)
Write-Host $username "last logged on at:" $dt }
Get-ADUserLastLogon -UserName $user
}
}
}
$resultList | export-csv -Path c:\users\admin\desktop\SamAccountName_results.csv -NoTypeInfo
Instead of this:
$user = ([adsisearcher]"(samAccountName=$($_.SamAccountName))").FindOne()
$resultList += New-Object -TypeName PSObject -Property #{
SamAccountName = $_.SamAccountName
Please do this:
$user = ([adsisearcher]"(samAccountName=$($_.SamAccountName))").FindOne()
$resultList += New-Object -TypeName PSObject -Property #{
SamAccountName = $_.SamAccountName
}