I'm trying to build a little app to help admins swap powerapps ownership around in PowerShell. I'm sure this is me misunderstanding how scopes work in PowerShell but I'm stumped and need a little help.
The app is pretty simple, it queries the PowerApp environment for a list of apps, their owners, and their GUIDs and presents them in a datagridview. Users select the app they're going to change, click a button, put an email address in, and then click another button. On that click, the app grabs the user's GUID from AAD and then runs a command to flip ownership of the app to that user's GUID.
But for some reason, the second function keeps reporting that the GUID and App Name I collected in the first screen are empty strings.
Here's the whole thing (minus credential info, natch):
#Get Apps on environment
$apps = Get-AdminPowerApp -EnvironmentName $powerAppEnv
#Form Details
$ChangePowerAppOwnership = New-Object system.Windows.Forms.Form
$ChangePowerAppOwnership.ClientSize = New-Object System.Drawing.Point(500,300)
$ChangePowerAppOwnership.text = "Change PowerApp Ownership"
$ChangePowerAppOwnership.TopMost = $false
$appsLabel = New-Object system.Windows.Forms.Label
$appsLabel.text = "Available Apps"
$appsLabel.AutoSize = $true
$appsLabel.width = 25
$appsLabel.height = 10
$appsLabel.location = New-Object System.Drawing.Point(15,20)
$appsLabel.Font = New-Object System.Drawing.Font('Segoe UI',10)
$availableApps = New-Object system.Windows.Forms.DataGridView
$availableApps.width = 470
$availableApps.height = 200
$availableApps.location = New-Object System.Drawing.Point(15,40)
$availableApps.MultiSelect = $false
$availableApps.SelectionMode = "FullRowSelect"
$availableApps.ColumnCount = 3
$availableApps.ColumnHeadersVisible = $true
$availableApps.Columns[0].Name = "App Name"
$availableApps.Columns[1].Name = "Current Owner"
$availableApps.Columns[2].Name = "GUID"
foreach($app in $apps){
$availableApps.Rows.Add(#($app.DisplayName,($app.Owner | Select-Object -Expand displayName),$app.AppName))
}
$promptForAdmin = New-Object system.Windows.Forms.Button
$promptForAdmin.text = "Next"
$promptForAdmin.width = 60
$promptForAdmin.height = 30
$promptForAdmin.location = New-Object System.Drawing.Point(424,260)
$promptForAdmin.Font = New-Object System.Drawing.Font('Segoe UI',10)
$promptForAdmin.Add_Click({ GetNewAdmin $availableApps.SelectedRows})
$adminLabel = New-Object system.Windows.Forms.Label
$adminLabel.text = "New Administrator"
$adminLabel.AutoSize = $true
$adminLabel.width = 25
$adminLabel.height = 10
$adminLabel.location = New-Object System.Drawing.Point(14,13)
$adminLabel.Font = New-Object System.Drawing.Font('Segoe UI',10)
$adminEmailField = New-Object system.Windows.Forms.TextBox
$adminEmailField.multiline = $false
$adminEmailField.width = 200
$adminEmailField.height = 20
$adminEmailField.location = New-Object System.Drawing.Point(135,12)
$adminEmailField.Font = New-Object System.Drawing.Font('Segoe UI',10)
$changeAppAdmin = New-Object system.Windows.Forms.Button
$changeAppAdmin.text = "Go"
$changeAppAdmin.width = 60
$changeAppAdmin.height = 30
$changeAppAdmin.location = New-Object System.Drawing.Point(424,260)
$changeAppAdmin.Font = New-Object System.Drawing.Font('Segoe UI',10)
$ChangePowerAppOwnership.controls.AddRange(#($appsLabel,$availableApps,$promptForAdmin))
$ChangePowerAppOwnership.ShowDialog()
function GetNewAdmin {
param($selectedRows)
$selectedAppGuid = $selectedRows | ForEach-Object{ $_.Cells[2].Value }
$selectedAppName = $selectedRows | ForEach-Object{ $_.Cells[0].Value }
Write-Host "Selected App GUID: $selectedAppGuid" #this and the following command show values
Write-Host "Selected App Name: $selectedAppName"
$appsLabel.Visible = $false
$availableApps.Visible = $false
$promptForAdmin.Visible = $false
$changeAppAdmin.Add_Click( { AssignNewAdmin $selectedAppGuid $selectedAppName $adminEmailField.Text} )
$ChangePowerAppOwnership.controls.AddRange(#($adminLabel,$adminEmailField,$changeAppAdmin))
}
function AssignNewAdmin {
param(
$selectedAppGuid,
$selectedAppName,
$newAdminEmail
)
Write-Host "AppID: $selectedAppGuid" #this is always empty
Connect-AzureAD -Credential $credentials
$user = Get-AzureADUser -ObjectId $newAdminEmail
$newAppOwnerGuid = $user | select ObjectId
$newAppOwnerName = $user | select DisplayName
$msgBoxMessage = "Are you sure you want to grant ownership of $selectedAppName to $newAppOwnerName`?"
$msgBoxInput = [System.Windows.Forms.MessageBox]::Show($msgBoxMessage,"Confirm","YesNo","Error")
switch ($msgBoxInput){
'Yes'{
Set-AdminPowerAppOwner -AppName $selectedAppGuid -EnvironmentName $powerAppEnv -AppOwner $newAppOwnerGuid
# try{
# $ChangePowerAppOwnership.Close()
# }
# catch{
# Write-Host "Could not update this app's administrator role."
# }
}
'No' {
$ChangePowerAppOwnership.Close()
}
}
}
Move the functions to the top or at least higher than $ChangePowerAppOwnership.ShowDialog() or the script wont find them(the execution stops till you close the Form...).
The same goes for the function AssignNewAdmin as it is used in GetNewAdmin but defined later.
Courtesy of Jeroen Mostert's comment, adding GetNewClosure to my second Add_Click function did the trick.
Related
`In a Powershell project - small GUI with Winforms - I need a passwordbox. I wrote a test-function but cannot manage to get the correct output ... I only get "Cancel"
I get the same result if I do not use
$inpBox.PasswordChar = "*"
[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
[System.Windows.Forms.Application]::EnableVisualStyles()
function InputForm {
param($loggedInUser="Spock")
$inpForm = New-Object System.Windows.Forms.Form
$inpForm.Height = 120
$inpForm.Width = 350
# $inpForm.Icon = "$PSScriptRoot\Heidelberg-H.ico"
$inpForm.Text = "Authentication Window"
$inpForm.MaximizeBox = $false
$inpForm.MinimizeBox = $false
$inpForm.FormBorderStyle = "FixedDialog"
$inpForm.StartPosition = "CenterScreen" # moves to center of screen
$inpForm.Topmost = $true # Make it Topmost
# create a Label
$inpLbl = New-Object System.Windows.Forms.Label
$inpLbl.Width = 300
$inpLbl.Location = New-Object System.Drawing.Point(10,10)
$inpLbl.Text = "Please type in the password for user: " + $loggedInUser
# create a InputBox for the password
$inpBox = New-Object System.Windows.Forms.TextBox
$inpBox.Width = 200
$inpBox.Height = 25
$inpBox.PasswordChar = "*"
$inpBox.Text = "********"
$inpBox.Location = New-Object System.Drawing.Point(10, 35)
# create an OK Button
$inpBtn = New-Object System.Windows.Forms.Button
$inpBtn.Width = 60
$inpBtn.Height = 25
$inpBtn.Text = "OK"
$inpBtn.Location = New-Object System.Drawing.Point(250,33)
$form.AcceptButton = $inpBtn
$inpForm.Controls.AddRange(#($inpLbl, $inpBox, $inpBtn))
# OK-Button - Click event
$inpBtn.Add_Click({
$inpForm.Close()
return $inpBox.Text
})
$inpForm.ShowDialog()
}
# MAIN
$PW = InputForm (Get-WMIObject -ClassName Win32_ComputerSystem).Username
write-host $PW
The problem is with this last part of your function:
$inpBtn.Add_Click({
$inpForm.Close()
return $inpBox.Text
})
$inpForm.ShowDialog()
Instead of registering a custom handler for the Click event, you'll want to assign a value to the DialogResult property on the button - then inspect that result and return the value of the textbox from the function:
$inpBtn.DialogResult = 'OK'
if($inpForm.ShowDialog() -eq 'OK'){
return $inpBox.Text
}
else {
throw "User canceled password prompt!"
}
Good afternoon, dear forum users. Please help me with the next question. I am trying to create a GUI application in Powershell GUI. Since I am a beginner in programming and knowledge, I have not decided to contact the forum for help. The essence of the application is to search by full name in the Active Directory accounts of the required employee account and view the date the password was changed for this account.
I have a ready-made code that works when entering an account login in English. At the same time, I want to implement a search in Russian. The code that I give below searches in Russian, but only in text form displays a list of accounts by name, this text can only be copied. I ask you to tell me how you can program the program so that it searches not in the form of text, full name, but in the form of elements on whose name you can click with the mouse cursor and get the result. I attach a screenshot of the program https://i.stack.imgur.com/GJ5qP.png. Thank you in advance for your help.
$Form.Size = New-Object System.Drawing.Size(460,350) # Mold size
$Form.Text ="Pass info"
$Form.AutoSize = $false
$Form.MaximizeBox = $false # button expand program
$Form.MinimizeBox = $true # minimize program button
$Form.BackColor = "#c08888" # Form color
$Form.ShowIcon = $true # Enable icon (upper left corner) $ true, disable icon
$Form.SizeGripStyle = [System.Windows.Forms.SizeGripStyle]::Hide # Prevent form stretching
#$Form.SizeGripStyle = "Hide"
$Form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::Fixed3D # Prevent form stretching _2
$Form.WindowState = "Normal"
$Form.StartPosition = "CenterScreen" #loads the window in the center of the screen
$Form.Opacity = 1.0 # Form transparency
$Form.TopMost = $false #
Over other windows
########### Function start:
function Info {
$wks=$InputBox.text;
Write-Host $wks
$regex1 = "[^-a-zA-Z0-9_#.!#]+"
$regex2 = "[^-а-яА-Я0-9_#.!#]+"
If($wks -match $regex2) {
$Result1=Get-ADUser -identity $wks -Properties * | select CN -ExpandProperty CN
$outputBox.text=$Result1
$Result2=Get-ADUser -identity $wks -Properties * | select PasswordLastset -ExpandProperty PasswordLastset
$outputBox2.text=$Result2
}
If($wks -match $regex1) {
$wks2 = "$wks*"
Write-Host $wks2
$Result3=Get-AdUser -Filter 'name -Like $wks2' | Select Name -expandproperty Name| Sort Name | fl | out-string
Write-Host $Result3
#$Result3 = ($Result3 -replace ' ','_')
#$Result3 = $Result3 -split '_',2 -join ' '
$ListBox.text = $Result3
}
}
########### End Function.
############################################## Start text fields
#### Group selection of labels 2 and 3$groupBox = New-Object System.Windows.Forms.GroupBox
$groupBox.Location = New-Object System.Drawing.Size(10,230)
$groupBox.size = New-Object System.Drawing.Size(280,80)
$groupBox.text = "Info:"
$Form.Controls.Add($groupBox)
$FormLabel1 = New-Object System.Windows.Forms.Label
$FormLabel1.Text = "User AD:"
$FormLabel1.ForeColor = "#3009f1"
$FormLabel1.Font = "Microsoft Sans Serif,8"
$FormLabel1.Location = New-Object System.Drawing.Point(10,10)
$FormLabel1.AutoSize = $true
$Form.Controls.Add($FormLabel1)
$FormLabel2 = New-Object System.Windows.Forms.Label
$FormLabel2.Text = "ФИО:"
$FormLabel2.Location = New-Object System.Drawing.Point(10,25)
$FormLabel2.ForeColor = "#3009f1"
$FormLabel2.Font = "Microsoft Sans Serif,8"
$FormLabel2.AutoSize = $true
#$Form.Controls.Add($FormLabel2) # Метка явл. частью общ. Form
$groupBox.Controls.Add($FormLabel2) # Метка явл. частью groupBox
$FormLabel3 = New-Object System.Windows.Forms.Label
$FormLabel3.Text = "Дата:"
$FormLabel3.Location = New-Object System.Drawing.Point(10,47)
$FormLabel3.ForeColor = "#3009f1"
$FormLabel3.Font = "Microsoft Sans Serif,8"
$FormLabel3.AutoSize = $true
#$Form.Controls.Add($FormLabel3) # Метка явл. частью общ. Form
$groupBox.Controls.Add($FormLabel3) # Метка явл. частью groupBox
############################################ InputBox #########################################
$InputBox = New-Object System.Windows.Forms.TextBox
$InputBox.Location = New-Object System.Drawing.Size(65,5)
$InputBox.Size = New-Object System.Drawing.Size(150,20)
$Form.Controls.Add($InputBox)
$outputBox = New-Object System.Windows.Forms.TextBox
$outputBox.Location = New-Object System.Drawing.Size(80,20)
$outputBox.Size = New-Object System.Drawing.Size(180,20)
$outputBox.ReadOnly = $True
$groupBox.Controls.Add($outputBox)
$outputBox2 = New-Object System.Windows.Forms.TextBox
$outputBox2.Location = New-Object System.Drawing.Size(80,42)
$outputBox2.Size = New-Object System.Drawing.Size(180,42)
$outputBox2.ReadOnly = $True
$groupBox.Controls.Add($outputBox2)
############################################## ListBox
$ListBox = New-Object System.Windows.Forms.TextBox
$ListBox.Location = New-Object System.Drawing.Size(65,30)
$ListBox.Size = New-Object System.Drawing.Size(220,200)
$ListBox.MultiLine = $True #declaring the text box as multi-line
$ListBox.AcceptsReturn = $true
$ListBox.ScrollBars = "Vertical"
$ListBox.AcceptsTab = $true
$ListBox.WordWrap = $True
$ListBox.ReadOnly = $True
$Form.Controls.Add($ListBox)
############################################## End ListBox
############################################## search in Russian and in English
$regex1 = "[^-a-zA-Z0-9_#.!#]+"
$regex2 = "[^-а-яА-Я0-9_#.!#]+"
$TestName = "Mouse" # Mouse или мышь
If($TestName -match $regex1){echo "English '$TestName'"}
If($TestName -match $regex2){echo "Русский '$TestName'"}
get-aduser -filter 'name -like "*" ' | select name -expandproperty name
############################################## End search in Russian and in English
################ Button
$Button = New-Object System.Windows.Forms.Button
$Button.Location = New-Object System.Drawing.Size(310,20)
$Button.Size = New-Object System.Drawing.Size(110,80)
$Button.Text = "Загрузить данные"
$Button.BackColor = "#d7f705"
$Button.Add_Click({Info})
$Form.Controls.Add($Button)
################ End Button
################ Binding a button in the program to the Enter key on the keyboard ...
$Form.KeyPreview = $True
$Form.Add_KeyDown({if ($_.KeyCode -eq "Enter")
{
# if enter, perform click
$Button.PerformClick()
}
})
################ End Binding a button
$Form.Add_Shown({$Form.Activate()})
[void] $Form.ShowDialog()
This is some example how is works:
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$MyForm = New-Object System.Windows.Forms.Form
$MyForm.Text = "USER info Lastlogondate"
$MyForm.Size = New-Object System.Drawing.Size(500, 500)
#user info
$allinfo=$null
#change your domin info
$allinfo=Get-ADUser -filter * -SearchBase "OU=users,DC=domain,DC=local" -properties Name, SamAccountName,Lastlogondate
#select in the column user name to fill $mTextBox1.Text
$Selectuser =
{
$c = $mDataGrid1.CurrentCell.columnindex
$colHeader = $mDataGrid1.columns[$c].name
if ($colHeader -eq "SamAccountName") {
$username = $mDataGrid1.CurrentCell.Value
$mTextBox1.Text = $username
Write-Host $username
}
} #
#usernema textbox--------------------------------------------
$mTextBox1 = New-Object System.Windows.Forms.TextBox
$mTextBox1.Text = ""
$mTextBox1.Top = "20"
$mTextBox1.Left = "26"
$mTextBox1.Anchor = "Left,Top"
$mTextBox1.Size = New-Object System.Drawing.Size(170, 23)
$MyForm.Controls.Add($mTextBox1)
#gridview
$mDataGrid1 = New-Object System.Windows.Forms.DataGridView
$mDataGrid1.Text = "DataGrid1"
$mDataGrid1.Top = "60"
$mDataGrid1.Left = "27"
$mDataGrid1.Anchor = "Left,Top"
$mDataGrid1.AutoSizeColumnsMode = 16
$mDataGrid1.add_CellContentDoubleClick($Selectuser)
$mDataGrid1.Size = New-Object System.Drawing.Size(400, 330)
$MyForm.Controls.Add($mDataGrid1)
#GetAllUsers button------------------------------------------
$mButton1 = New-Object System.Windows.Forms.Button
$mButton1.Text = "Get All Users"
$mButton1.Top = "20"
$mButton1.Left = "200"
$mButton1.Anchor = "Left,Top"
$mButton1.Size = New-Object System.Drawing.Size(100, 23)
$MyForm.Controls.Add($mButton1)
$mButton1.Add_Click( { GetAllusers})
Function GetAllusers {
$mDataGrid1.DataSource = $null
$array = New-Object System.Collections.ArrayList
$result=$allinfo |Select-Object Name, SamAccountName,Lastlogondate|sort -Property Name
$array.Addrange($result)
$mDataGrid1.Datasource = ($array)
$MyForm.Refresh()
}
#exit---------------------------------------------------------
$mButton4 = New-Object System.Windows.Forms.Button
$mButton4.Text = "Exit"
$mButton4.Top = "20"
$mButton4.Left = "320"
$mButton4.Anchor = "Left,Top"
$mButton4.Size = New-Object System.Drawing.Size(120, 23)
$mButton4.Add_Click( {$MyForm.Close()})
$MyForm.Controls.Add($mButton4)
$MyForm.ShowDialog()
I created a series of scripts for creating domain users. Since every domain where we create users requires different parameters and conditions, I have one script for each domain. But in case of one domain I have a problem. For this domain the manual procedure is like this:
1) open dsa.msc
2) connect to the "xyz" domain (the user is being created from a server in "abc" domain)
3) Create the user (operation for 10 to 15 minutes, that's why I created the scripts)
Unfortunately, when I run my script, I get the error message, that "The server is unwilling to process the request" (That's the precise complete error message) during execution of New-ADUser cmdlet. I suppose the reason is the need to perform the step 2 in the procedure I described above. So I somehow need to simulate it in the script, but I have no idea how to do that.
This is how the command is defined:
$params = #{
'GivenName' = $First_name_val.Text
'Surname' = $Second_name_val.Text
'DisplayName' = $Display_name
'AccountPassword' = $password
'Path' = $Location_val.Text
'Name' = $User_name_val.Text
'CannotChangePassword' = $Cannot_chg_pass.Checked
'PasswordNeverExpires' = $Pass_not_expires.Checked
'ChangePasswordAtLogon' = $Must_chg_pass.Checked
'Enabled' = !($Account_disabled_val.Checked)
'Description' = $GECOS_val.Text
'Office' = "NA"
'OfficePhone' = "NA"
'Title' = $Job_Title_val.Text
'Department' = $Department_val.Text
'Company' = $Company_val.Text
'SamAccountName' = $User_name_val.Text
'UserPrincipalName' = $User_name_val.Text + "#woodplc.com"
'EmailAddress' = $Email_Address_val.Text
'PassThru' = $true
}
$New_user = New-ADUser #params
Definition of $User_name_val.Text is here:
#region Real name of the user
[void]$AD_user_creation.SuspendLayout()
$Display_name_lbl = New-Object system.Windows.Forms.Label
$Display_name_lbl.text = "User`'s real name"
$Display_name_lbl.AutoSize = $true
$Display_name_lbl.width = 25
$Display_name_lbl.height = 10
$Display_name_lbl.location = New-Object System.Drawing.Point(10,10)
$First_name_val = New-Object system.Windows.Forms.TextBox
$First_name_val.Text = "a."
$First_name_val.multiline = $false
$First_name_val.width = 120
$First_name_val.height = 20
$First_name_val.location = New-Object System.Drawing.Point(200,10)
$Second_name_val = New-Object system.Windows.Forms.TextBox
$Second_name_val.multiline = $false
$Second_name_val.width = 120
$Second_name_val.height = 20
$Second_name_val.location = New-Object System.Drawing.Point(330,10)
$Display_name_val = New-Object system.Windows.Forms.Label
$Display_name_val.Text = ""
$Display_name_val.width = 250
$Display_name_val.height = 20
$Display_name_val.location = New-Object System.Drawing.Point(200,40)
$showFullName = { $Display_name_val.Text = ($First_name_val.Text + "." + $Second_name_val.Text) }
[void]$Second_name_val.Add_Leave( { & $showFullName } )
[void]$First_name_val.Add_Leave( { & $showFullName } )
#endregion
#region User name of the user
$User_name_lbl = New-Object system.Windows.Forms.Label
$User_name_lbl.text = "User logon name"
$User_name_lbl.AutoSize = $true
$User_name_lbl.width = 25
$User_name_lbl.height = 10
$User_name_lbl.location = New-Object System.Drawing.Point(10,70)
$User_name_val = New-Object system.Windows.Forms.TextBox
$User_name_val.multiline = $false
$User_name_val.width = 250
$User_name_val.height = 20
$User_name_val.location = New-Object System.Drawing.Point(200,70)
$LogonName = {$User_name_val.Text = ($First_name_val.Text + "." + $Second_name_val.Text)}
[void]$Second_name_val.Add_Leave({& $LogonName})
[void]$First_name_val.Add_Leave({& $LogonName})
[void]$AD_user_creation.ResumeLayout()
#endregion
The error "The server is unwilling to process the request" means that some of your input values are invalid. For example, the OU you are providing could be invalid (maybe a space that shouldn't be there), or the SamAccountName might be too long or contain an invalid character, etc.
If you show the full command you are using I might be able to spot something.
If there was an issue connecting to the server or authenticating, then the error message would be different.
I ma working on a form that will search all connected drives for PST files.
I can get it working with the following command:-
Get-PSDrive -PSProvider "filesystem"|%{get-childitem $_.root -include *.pst -r}|select name, directoryname, #{name="Size (GB)";expression ={"{0:N2}" -f ($_.length/1GB)}}
The only problem is it takes about 45 minutes to run through all the drives and finish the search. I was thinking of trying to speed it up by using the windows search index.
I have got this....
function Searchindex{
$query="SELECT System.ItemName, system.ItemPathDisplay, System.ItemTypeText, System.Size FROM SystemIndex where system.itemtypetext = 'outlook data file'"
$objConnection = New-Object -ComObject adodb.connection
$objrecordset = New-Object -ComObject adodb.recordset
$objconnection.open("Provider=Search.CollatorDSO;Extended Properties='Application=Windows';")
$objrecordset.open($query, $objConnection)
$array=#()
Try { $objrecordset.MoveFirst() }
Catch [system.exception] { "no records returned" }
do
{
Write-host ($objrecordset.Fields.Item("System.ItemName")).value `
($objrecordset.Fields.Item("System.ItemPathDisplay")).value `
($objrecordset.Fields.Item("System.ITemTypeText")).value `
($objrecordset.Fields.Item("System.Size")).value
if(-not($objrecordset.EOF)) {$objrecordset.MoveNext()}
} Until ($objrecordset.EOF)
$objrecordset.Close()
$objConnection.Close()
$objrecordset = $null
$objConnection = $null
[gc]::collect()
}
this outputs the details to the screen in a few seconds which is perfect but I can't work out how to display it in a datagrid view.
I am using primal form to create the forms.
Once the data is populated in the datagridview I want to be able to select records and copy them to a new location
Can anyone help?
TIA
Andy
I'm not familiar with DataGridView but I feel if you had an object you would be better capable to manipulate it.
function Searchindex{
$query="SELECT System.ItemName, system.ItemPathDisplay, System.ItemTypeText, System.Size FROM SystemIndex where system.itemtypetext = 'outlook data file'"
$objConnection = New-Object -ComObject adodb.connection
$objrecordset = New-Object -ComObject adodb.recordset
$objconnection.open("Provider=Search.CollatorDSO;Extended Properties='Application=Windows';")
$objrecordset.open($query, $objConnection)
$array=#()
Try { $objrecordset.MoveFirst() }
Catch [system.exception] { "no records returned" }
do
{
$array += [pscustomobject]#{
Name = ($objrecordset.Fields.Item("System.ItemName")).value
Path = ($objrecordset.Fields.Item("System.ItemPathDisplay")).value
TypeText = ($objrecordset.Fields.Item("System.ITemTypeText")).value
Size = ($objrecordset.Fields.Item("System.Size")).value
}
If(-not($objrecordset.EOF)) {$objrecordset.MoveNext()}
} Until ($objrecordset.EOF)
$objrecordset.Close()
$objConnection.Close()
$objrecordset = $null
$objConnection = $null
[gc]::collect()
$array
}
This will send out a custom PowerShell object array. You already had the variable $array initialized. We just needed to populate it.
Then you could use something like this to filter out the files you are looking for.
Searchindex | Out-GridView -PassThru
After hitting Ok it will only output the records selected.
DataGridView
with multiselect and return
$global:results = #()
#...searchindex function is here ....
$form = New-Object System.Windows.Forms.Form
$form.Size = New-Object System.Drawing.Size(900,600)
$dataGridView = New-Object System.Windows.Forms.DataGridView
$dataGridView.Size=New-Object System.Drawing.Size(800,400)
$dataGridView.SelectionMode = 'FullRowSelect'
$dataGridView.MultiSelect = $true
$go = New-Object System.Windows.Forms.Button
$go.Location = New-Object System.Drawing.Size(300,450)
$go.Size = New-Object System.Drawing.Size(75,23)
$go.text = "Select"
$form.Controls.Add($go)
$form.Controls.Add($dataGridView)
$arraylist = New-Object System.Collections.ArrayList
$arraylist.AddRange((Searchindex))
$dataGridView.DataSource = $arraylist
$dataGridView.Columns[0].width = 240
$go.Add_Click(
{
$dataGridView.SelectedRows| ForEach-Object{
$global:results += [pscustomobject]#{
Name = $dataGridView.Rows[$_.Index].Cells[0].Value
Path = $dataGridView.Rows[$_.Index].Cells[1].Value
TypeText = $dataGridView.Rows[$_.Index].Cells[2].Value
Size = $dataGridView.Rows[$_.Index].Cells[3].Value
}
$form.Close()
}
})
$form.ShowDialog()
$global:results
There is a lot to cover here but look at the examples and let me know how this works for you. It will return all selected rows back as objects in the global variable $global:results. It needs to be global as output does not persist outside the $go.Add_Click. The searchindex function is there but omitted in the second code sample to save space.
I'm still a beginner with powershell, but love to learn and research all the things it can do.
So with that, I am looking to create a script that will output to a datagridview table. I created a simple enough form that has a multi-line text box where you can enter in a list of servers and then just a simple "check" button that calls my function to actually query each server for their services and outputs that info into the datagridview below it.
That part was easy enough for me to create. My thing is, I want it to do the following":
query each server and pull the list of all services on that server
then in the datagridview, I want it to show the service name in column 1, and then the count of how many servers have that service in column 2
Hope this make since. Can't really provide any code as I don't know how to properly write it! I'm thinking there is someway to generate the full list, then do a loop and count type thing, but not sure.
I thank you for any assistance with this. Been googling and reading up like crazy. Either not correct search criteria or something just isn't clicking for me.
Update - Adding in current script I have:
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$xForm = 800
$yForm = 800
$SVCForm = New-Object System.Windows.Forms.Form
$SVCForm.Text = "Automatic Services Query"
$SVCForm.Size = New-Object System.Drawing.Size($xForm,$yForm)
$SVCForm.FormBorderStyle = "FixedSingle"
$SVCForm.StartPosition = "CenterScreen"
$SVCForm.ControlBox = $true
$SVCForm.KeyPreview = $True
$SVCForm.ShowIcon = $false
$SVCForm.MinimizeBox = $True
$SVCForm.MaximizeBox = $false
$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Size(365,720)
$CancelButton.Size = New-Object System.Drawing.Size(75,23)
$CancelButton.Text = "Cancel"
$CancelButton.Add_Click({$x=$CancelButton.Text;$SVCForm.Close()})
$SVCForm.Controls.Add($CancelButton)
$ServerListGroup = New-Object System.Windows.Forms.GroupBox
$ServerListGroup.Location = New-Object System.Drawing.Size(5,10)
$ServerListGroup.size = New-Object System.Drawing.Size(780,300)
$ServerListGroup.text = "Enter list of servers you want to check:"
$SVCForm.Controls.Add($ServerListGroup)
$ServerList = New-object System.Windows.Forms.TextBox
$ServerList.Location = New-object System.Drawing.Size(5,25)
$ServerList.Size = New-Object System.Drawing.Size(280,270)
$ServerList.Multiline = $True
$ServerList.ScrollBars = "Vertical"
#$ServerList.add_TextChanged({ONValButton})
$ServerListGroup.Controls.Add($ServerList)
$SVCButton = New-Object System.Windows.Forms.Button
$SVCButton.Location = New-Object System.Drawing.Size(505,140)
$SVCButton.Size = New-Object System.Drawing.Size(180,22)
$SVCButton.Text = "SVC Check"
$SVCButton.Enabled = $True
$SVCButton.Add_Click({SvcCheckCount})
$ServerListGroup.Controls.Add($SVCButton)
$SvcListGroup = New-Object System.Windows.Forms.GroupBox
$SvcListGroup.Location = New-Object System.Drawing.Size(5,330)
$SvcListGroup.size = New-Object System.Drawing.Size(780,380)
$SvcListGroup.text = "Automatic Running/Not-Running Services are listed below:"
$SVCForm.Controls.Add($SvcListGroup)
#$SvcList = New-object System.Windows.Forms.TextBox
#$SvcList.Location = New-object System.Drawing.Size(5,25)
#$SvcList.Size = New-Object System.Drawing.Size(765,350)
#$SvcList.Multiline = $True
#$SvcList.ScrollBars = "Vertical"
#$SvcList.Readonly= $True
#$SvcListGroup.Controls.Add($SvcList)
$SvcGrid = New-Object System.Windows.Forms.DataGridView
$SvcGrid.Location = New-Object System.Drawing.Size(5,15)
$SvcGrid.Size = New-Object System.Drawing.Size(760,360)
$SvcGrid.ColumnHeadersBorderStyle = [System.Windows.Forms.DataGridViewHeaderBorderStyle]::Single
$SvcGrid.CellBorderStyle = [System.Windows.Forms.DataGridViewCellBorderStyle]::Single
$SvcGrid.ColumnHeadersHeightSizeMode = [System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode]::DisableResizing
$SvcGrid.GridColor = [System.Drawing.Color]::Black
$SvcGrid.RowHeadersVisible = $false
$SvcGrid.AllowUserToAddRows = $false
$SvcGrid.AllowUserToResizeColumns = $False
$SvcGrid.AllowUserToResizeRows = $false
$SvcGrid.ColumnHeadersHeight = 23
$SvcGrid.SelectionMode = [System.Windows.Forms.DataGridViewSelectionMode]::FullRowSelect
$Scroll = New-Object System.Windows.Forms.VScrollBar
$Scroll.Dock = [System.Windows.Forms.DockStyle]::Right
$Scroll.width = 18
$Scroll.isAccessible = $false
$SvcGrid.Controls.Add($Scroll)
$SvcGrid.Columns.Add("Name","Service Name") > $null
$SvcGrid.Columns["Name"].Width = 200
$SvcGrid.Columns["Name"].HeaderCell.Style.Alignment = [System.Windows.Forms.DataGridViewContentAlignment]::MiddleLeft
$SvcGrid.Columns["Name"].DefaultCellStyle.Alignment = [System.Windows.Forms.DataGridViewContentAlignment]::MiddleLeft
$SvcGrid.Columns["Name"].ReadOnly = $False
$SvcGrid.Columns.Add("StartMode", "Start Mode") > $null
$SvcGrid.Columns["StartMode"].Width = 180
$SvcGrid.Columns["StartMode"].HeaderCell.Style.Alignment = [System.Windows.Forms.DataGridViewContentAlignment]::MiddleLeft
$SvcGrid.Columns["StartMode"].DefaultCellStyle.Alignment = [System.Windows.Forms.DataGridViewContentAlignment]::MiddleLeft
$SvcGrid.Columns["StartMode"].ReadOnly = $False
$SvcGrid.Columns.Add("Running","Running") > $null
$SvcGrid.Columns["Running"].Width = 180
$SvcGrid.Columns["Running"].HeaderCell.Style.Alignment = [System.Windows.Forms.DataGridViewContentAlignment]::MiddleCenter
$SvcGrid.Columns["Running"].DefaultCellStyle.Alignment = [System.Windows.Forms.DataGridViewContentAlignment]::MiddleCenter
$SvcGrid.Columns["Running"].ReadOnly = $true
$SvcGrid.Columns.Add("NotRunng","Not Running")>$null
$SvcGrid.Columns["NotRunng"].Width = 180
$SvcGrid.Columns["NotRunng"].HeaderCell.Style.Alignment = [System.Windows.Forms.DataGridViewContentAlignment]::MiddleCenter
$SvcGrid.Columns["NotRunng"].DefaultCellStyle.Alignment = [System.Windows.Forms.DataGridViewContentAlignment]::MiddleCenter
$SvcGrid.Columns["NotRunng"].ReadOnly = $true
$SvcListGroup.Controls.Add($SvcGrid)
Function SvcCheckCount
{
$SvcGrid.Rows.Clear()
$Servername = $ServerList.Text.Split("`n")|%{$_.trim()}
foreach($Server in $Servername)
{
$Server = $Server.ToUpper()
$svctest = Get-WmiObject Win32_Service | Where-Object {$_.StartMode -eq 'Auto'} | Select-Object Name, Startmode, State
Foreach ($svc in $svctest)
{
$name = $svc.Name
$startmode = $svc.StartMode
$state = $svc.State
If($state-eq"Running"){$SvcGrid.Rows.add($name,$startmode,$state)}
If($state-eq"Stopped"){$SvcGrid.Rows.add($name,$startmode,$null,$state)}
}
}
}
$SVCForm.Topmost = $True
$SVCForm.Add_Shown({$SVCForm.Activate()})
[void] $SVCForm.ShowDialog()
Since you already have the GUI portion of this functioning I am going to focus us the grouping of the data you are looking for. Going into this the one thing I am fuzzy on is why you have the if statements are for but we can work on that if need be. The following is meant to be in place of your foreach loop
$services = #()
foreach($Server in $Servername){
$Server = $Server.ToUpper()
$services += Get-WmiObject Win32_Service -ComputerName $Server -Filter 'StartMode="Auto"' |
Select-Object Name, Startmode, State |
Add-Member -MemberType NoteProperty -Value $Server -Name "Server" -PassThru
}
$services | Group-Object Name | ForEach-Object{
$SvcGrid.Rows.add($_.Name,$_.Count)
}
First thing: you were not using the $server variable in your wmi call so all the results would have been from the one machine you were running this from. Also, I moved the Where into a -Filter so that should speed up processing on remote machines.
Collect all of this information into an array (adding the computer name in case it becomes useful later). Then, using the results from that use Group-Object to get the counts you were looking for. Pipe that into another ForEach-Object to get the results in your grid ( which i have not tested.)
Side note: If you just want the info in a grid you can use Out-GridView
$services | Group-Object Name | Select name,count | Out-GridView