How do I manipulate data out of a variable in powershell - sql

I have a power-shell script with which I am trying to back up a constantly changing number of SQL databases. Fortunately all of these databases are listed in a registry key. I am leveraging this in a for-each loop. The issue that I am having is that after grabbing the registry value that I want, when I try to pass it into my function to back up the databases there seems to be information in the variable that I can get rid of. If I output the contents of the variable to the screen by just calling the variable ($variable) is shows just fine. But if I write-host the variable to the screen the extra "content" that shows up when calling the function also shows up.
Here is the part of the script that generates the contents of the variable.
foreach ($childitem in get-childitem "HKLM:\SOFTWARE\Wow6432Node\Lanovation\Prism Deploy\Server Channels")
{$DBName = get-itemproperty Registry::$childitem | select "Channel Database Name"
write-host $DBname}
Here is what write-host displays :
#{Channel Database Name=Prism_Deploy_Sample_268CBD61_AC9E_4853_83DE_E161C72458DE}
but what I need is only this part :
Prism_Deploy_Sample_268CBD61_AC9E_4853_83DE_E161C72458DE
I have tried looking online at how to do this, and what I've found mentions things similar to $variable.split and then specifying my delimiters. But when I try this I get an error saying "Method invocation failed because [System.Management.Automation.PSCustomObject] doesn't contain a method named 'split'."
I'm at a loss as to where to go from where I'm at currently.

select-object will return an object that has the named properties that you "select". To get just value of that property, just access it by name:
write-host $DBname."Channel Database Name"

Sounds like it's returning a hash table row object.
Try
write-host $DBName.value
or, failing that, do a
$DBName | Get-member
When in doubt, get-member gives you a nice idea of what you are dealing with.

You should be able to write
foreach ($childitem in get-childitem "HKLM:\SOFTWARE\Wow6432Node\Lanovation\Prism Deploy\Server Channels")
{$DBName = get-itemproperty Registry::$childitem | select "Channel Database Name"
write-host $DBname.Name}
to get what you are looking for

Related

Powershell - Comparing LineNumbers of lines that match

I'm having trouble to come up with solution that would compare LineNumbers of matching pairs from two lists. I will show you what I mean on example.
I have one SQL script, where I am inserting some data into existing tables. For ensuring repeatability of the script, before every insert into I am deleting the previous content of the table with "delete" statement. I am able to parse the file and check If every "insert into database1.table1" also have "delete from database1.table1" in the file. But i don't know how to check if the delete statement of the particular table is before the insert into statement (you need to delete the content of the table before you load new data into it). I figured I would need to use the LineNumber property, but I really don't know how to combine it with the database.table check.
This is what i got into first variable with this command:
$insertinto = Get-ChildItem "$packagepath\Init\" -Include 03_Init_*.txt -Recurse | Select-String -Pattern "insert into "
#content of variable
C:\Users\hanus\Documents\sql_init.txt:42:insert into database1.table1
C:\Users\hanus\Documents\sql_init.txt:130:insert into database1.table2
C:\Users\hanus\Documents\sql_init.txt:282:insert into database2.table3
Here is what I got into second variable with this command:
$deletefrom = Get-ChildItem "$packagepath\Init\" -Include 03_Init_*.txt -Recurse | Select-String -Pattern "delete from "
#content of the variable
C:\Users\hanus\Documents\sql_init.txt:40:delete from database1.table1;
C:\Users\hanus\Documents\sql_init.txt:128:delete from database1.table2;
C:\Users\hanus\Documents\sql_init.txt:280:delete from database2.table3;
The expected output would be something like: This"delete from" statement is not before "insert into" statement, even though it's in the file.
I hope I described the problem well. I am new to Powershell and scripting so be please patient with me. Thank you for any help in advance!
You're already using Select-String, so this should be pretty simple. The content of those variables is far more than you're seeing there. Run this:
$deletefrom | Format-List * -Force
You'll see that each match contains an object with properties for what file the match is from, what line number the match was found on, and more. I think if you capture the table that is being modified in your Select-String with a look behind of what you're searching on now you could group on that, and then alert on times where the delete happens after the insert.
Get-ChildItem "$packagepath\Init\*" -Include 03_Init_*.txt -Recurse |
Select-String "(?<=delete from |insert into )([^;]+)" |
Group-Object {$_.Matches[0].value} |
ForEach-Object {
if($_.group[0] -notmatch 'delete from'){Write-Warning "Inserting into $($_.Name) before deleting"}
}

Powershell script as a step in sql job giving error

I am trying to create a sql job which syncs users from a csv file to ad group.
My powershell script is one of the steps of this job. Issue is that my script is supposed to run on another server which has Active Directory but i keep on getting error when i run this step.
My script is following:
invoke-Command -Session Server-Name
Import-Module activedirectory
$ADUsers = Import-csv \\Server-Name\folder\file.csv
foreach ($User in $ADUsers)
{
$Username = $User.sAMAccountName
$group=$user.adgroup
if (Get-ADUser -F {SamAccountName -eq $Username})
{
foreach($group in $groups){Add-ADGroupMember -identity $group -Members $Username}
Write-Output "$username has beeen added to group $group"
}
}
Error i am getting is
Executed as user: Username. A job step received an error at line 2 in a PowerShell script. The corresponding line is 'Invoke-Command -Session Server-Name. Correct the script and reschedule the job. The error information returned by PowerShell is: 'Cannot bind parameter 'Session'. Cannot convert the "Server-Name" value of type "System.String" to type "System.Management.Automation.Runspaces.PSSession". '. Process Exit Code -1. The step failed.
server name has '-' in between so need to know if that is causing the issue
or i am using wrong way to run this script on a different server from a sql job
Any help would be appreciated!
Jaspreet I am not expert on powershell but seems like you are passing the wrong parameters.Just referring to Microsoft docs seems like you need to pass the computer name rather than -Session
Try with this line of code at starting
invoke-Command -ComputerName Server-Name.
For more please refer Microsoft docs
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/invoke-command?view=powershell-6#examples

VB.net and powershell variables

I have a Visual Studio form running with VB.net and I'm collecting info needed to setup an AD user. In the end, this info will need to simply be passed to Powershell with no return info needed. Before that though, I need it to check if a printer code has already been assigned to someone before allowing it to be submitted to another user. I have a simple powershell script written up for it.
(We use the Pager field to store the printer code.)
Import-Module ActiveDirectory
$Page = $args[0]
Get-ADUser -Filter { Pager -like $Page } | FT Name
I setup the code I found HERE, and attempted to modify it to my script but it keeps crashing on
Dim results As Collection(Of PSObject) = MyPipeline.Invoke()
It gives me: An unhandled exception of type 'System.Management.Automation.ParseException' occurred in System.Management.Automation.dll
If I run his little 6+5 basic example script, it works, but when I try to retrieve info and return a name, it doesn't like it. How can I get it to return the name of the person if it find it? And since it won't run, I'm not even sure if passing the printer code as $args[0] is going to work yet.
Your results is expecting a collection of PowerShell objects. When you pipe the Get-ADUser command to Format-Table, it effectively strips the object down to a stream of strings. Try without the | FT Name.
Import-Module ActiveDirectory #if you're using powershell 3 or later, this may be redundant
# $Page = $args[0] # don't need to do this
$results = Get-ADUser -Filter { Pager -like $args[0] }
Write-Verbose $results
#Write-Verbose $results.Name #try this if the above one works
Update:
Write-Verbose may be causing an issue.
Try this:
Get-ADUser -Filter { Pager -like $args[0] }
Just that one line as the total PS code. (Assuming you have PowerShell 3.0 or later, you don't need Import-Module) That line will return objects of type TypeName: Microsoft.ActiveDirectory.Management.ADUser (from `Get-ADUser username | Get-Member).
You may also be able to use the .Net object type directly, without PowerShell. I'm not knowledgeable about .NET beyond what I picked up working with PowerShell.
Accessing AD using .NET, info from MSDN.

Why does this work (or how)?

In my email today I received an email about getting unused drive letters. This was their solution:
Get-ChildItem function:[d-z]: -Name | Where-Object {-not (Test-Path -Path $_)}
PowerShell Magazine BrainTeaser had this for a solution, same thing.
ls function:[d-z]: -n|?{!(test-path $_)}|random
I have no idea how function:[d-z]: works. I know that for each character between 'd' to 'z' is used but I don't know why the syntax works.
Testing Get-ChildItem function:[d-a]: -Name gives you an error saying Get-ChildItem : Cannot retrieve the dynamic parameters for the cmdlet. The specified wildcard pattern is not valid:[d-a]:
So is that a dynamic parameter? How come is does not show up with Get-Help gci -full?
function: is a PSDrive which exposes the set of functions defined in the current session. PowerShell creates a function for each single letter drive, named as the letter followed by a colon.
So, function:[d-z]: lists the functions from "d:" through "z:"
function:[d-a]: doesn't work because , d-a isn't a range of letters.

powershell assigning output of a ps1 script to a variable

Let me start with I am very new to powershell and programming for that matter. I have a powershell script that takes some arguments and that outputs a value.
The result of the script is going to be something like 9/10 where 9 would be the number active out of the total amount of nodes. I want to assign the output to a variable so I can then call another script based on the value.
This is what I have tried, but it does not work:
$active = (./MyScript.ps1 lb uid **** site)
I have also tried the following which seems to assign the variable an empty string
$active = (./MyScript.ps1 lb uid **** site | out-string)
In both cases they run and give me the value immediately instead of assigning it to the variable. When I call the variable, I get no data.
I would embrace PowerShell's object-oriented nature and rather than output a string like "9/10", create an object with properties like NumActiveNodes and TotalNodes e.g. in your script output like so:
new-object psobject -Property #{NumActiveNodes = 9; TotalNodes = 10}
Of course, substitute in the dynamic values for num active and total nodes. Note that uncaptured objects will automatically appear on your script's output. Then, if this is your scripts only output, you can do this:
$obj = .\MyScript.ps1
$obj.NumActiveNodes
9
$obj.TotalNodes
10
It will make it nicer for those consuming the output of your script. In fact the output is somewhat self-documenting e.g.:
C:\PS> .\MyScript.ps1
NumActiveNodes TotalNodes
-------------- ----------
9 10
P.S. When did StackOverflow start sucking so badly at formatting PowerShell script?
If you don't want to change the script ( and assuming only that $avail_count/$total_count line is written by the script), you can do:
$var= powershell .\MyScript.ps1
Or just drop the write-host and have just $avail_count/$total_count
and then do:
$var = .\MyScript.ps1
you could just do a $global:foobar in your script and it will persist after the script is closed
I know, the question is a bit older, but it might help someone to find the right answer.
I had the similar problem with executing PS script with another PS script and saving the output into variable, here are 2 VERY good answers:
Mathias
mklement0
Hope it helps!
Please up-vote them if so, because they are really good!