Is it possible to backup Powershell objects using Export-clixml - object

Is it valid to export objects in powershell using Export-clixml and use the .xml file as a backup?
I'm going to do a massive deletion of thousand of MailContacts in my forest and i want to do a backup of all those MailContacts before i delete them
Thanks in advance,
O.Z

I would say no because when you read the objects back in, PowerShell doesn't recreate the original MailContact objects. It creates an object of a special type representing only the public data fields of the original object. If you were to execute this:
Start-Process notepad
Get-Process notepad | Export-Clixml notepad.clixml
Stop-Process -name notepad
And then import the clixml file like so and dump it to the screen:
PS> $n = Import-Clixml .\notepad.clixml
PS> $n
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
78 7 1280 5916 96 0.06 32752 notepad
It looks like you have a notepad process running but the Import-CliXml hasn't recreated the Notepad process. And you will notice the deserialized object doesn't have any of the Process methods like Kill() or WaitForExit(). That's because the imported object contains only a snapshot of the original object's data. There is no feasible way to make the normal methods work on an object like this. You can see this by running the imported object through Get-Member:
PS> $n | Get-Member
TypeName: Deserialized.System.Diagnostics.Process
Name MemberType Definition
---- ---------- ----------
GetType Method type GetType()
ToString Method string ToString(), string ToString(string format, System.IFormatProvider for...
Company NoteProperty System.String Company=Microsoft Corporation
CPU NoteProperty System.Double CPU=0.0625
...
Note the type name Deserialized.System.Diagnostics.Process.
Now this is not to say that you couldn't use the data from these objects to manually reconstruct the MailContacts but I would look for a more direct route. For instance, couldn't you backup the file the MailContacts are contained in - assuming they are stored in a file? Or perhaps there is an API to allow saving contacts to a file?

Related

Looking to validate that certain string is present in a text file, send warning if not

I have a process where files containing data are generated in separate locations, saved to a networked location, and merged into a single file.
And the end of the process, I would like to check that all locations are present in that merged file, and notify me if not.
I am having a problem finding a way to identify that a string specific to each location isn't present, to be used in an if statement, but it doesn't seem to be identifying the string correctly?
I have tried :
get-childitem -filter *daily.csv.ready \\x.x.x.x\data\* -recurse | where-object {$_ -notin 'D,KPI,KPI,1,'}
I know it's probably easier to do nothing if it is present, and perform the warning action if not, but I'm curious if this can be done in the reverse.
Thank you,
As Doug Maurer points out, your command does not search through the content of the files output by the Get-ChildItem command, because what that cmdlet emits are System.IO.FileInfo (or, potentially, System.IO.DirectoryInfo) instances containing metadata about the matching files (directories) rather than their content.
In other words: the automatic $_ variable in your Where-Object command refers to an object describing a file rather than its content.
However, you can pipe System.IO.FileInfo instances to the Select-String cmdlet, which indeed searches the input files' content:
Get-ChildItem -Filter *daily.csv.ready \\x.x.x.x\data\* -Recurse |
Where-Object { $_ | Select-String -Quiet -NotMatch 'D,KPI,KPI,1,' }

Powershell: How to get the location of a file, depending on its name?

So my task is to write a PS script, that outputs the location of a database file. The location of the file is:
C:\Program Files\Microsoft\Exchange Server\V15\Mailbox\Mailbox database Name\Mailbox database Name.edb
I figured I can get the name of my Exchange database with
Get-MailboxDatabase | fl Name
which has the output:
Mailbox Database 0161713049
which is the name of the db but there is a bunch of invisible characters before and after the actual name.
So my question is, how could I get rid of these invisible characters? I want to concat a string to make it look like this:
C:\Program Files\Microsoft\Exchange Server\V15\Mailbox\Mailbox Database 0161713049\Mailbox Database 0161713049.edb
I would need this code to work on servers with completely different database names too, so simply removing the unwanted characters from the start with .Remove() may help, but since I don't know for sure the length of the name of the database, I can't remove the characters at the end.
Also I can't get rid of the feeling that there is a much simpler way to get the location of my .edb file.
Powershell treats almost all outputs as an object with properties in hashtable format like #{Name=MYEXCHDB}. When you just want a property value as a string instead, you must expand it like #AdminOfThings suggests:
Get-MailboxDatabase | Select-Object -ExpandProperty Name
To concatenate the name into a string:
$myString = "C:\path\to\$(Get-MailboxDatabase | Select-Object -ExpandProperty Name)"
And as #mathias-r-jessen suggests, the path to the database is another property you can get directly:
Get-MailboxDatabase | Select-Object -ExpandProperty EdbFilePath | Select-Object -ExpandProperty PathName

get the whole value of powershell objects

I am executing a Get-ADDomain command
I was fetching the output given by the command
And I noticed that it is not giving the full list of objects it is just listing some of those and then end with ... have attached the image for reference
I realized it might be problem with the width of the output and it must be using the default width
So while executing the command I also set Out-Width as 1000 but it gives more values but still the same problem persists and increasing the width any further does not have any impact on the output
Is there any way by which I can capture the whole value itself. I have faced this issue with other commands as well. This is the command I executed :
Get-ADDomain | Select-Object LinkedGroupPolicyObjects| Out-String -Width 1000
You should use -ExpandProperty and work with the objects, rather then converting them to a string with out-string.
$LinkedGPOs = Get-ADDomain | Select-Object -ExpandProperty LinkedGroupPolicyObjects
foreach($LinkedGPO in $LinkedGPOs) {
}

how do you select just one property from an array of "results" from the Azure command 'az group list in powershell'?

I am trying to select just one property from an array of "result" (objects?) which come back from the Azure command az group list in powershell?
I know this sounds trivial, but here's where it gets strange, and I hope there is a simple explanation.
If I run the Azure command az group list -o table (after I have succesfully logged in using az login) I get the following typical response
PS src> az group list -o table
Name Location Status
---------------- ---------- ---------
group0 westeurope Succeeded
group1 westeurope Succeeded
group2 uksouth Succeeded
group3 westeurope Succeeded
group4 westeurope Succeeded
group5 westeurope Succeeded
group6 westeurope Succeeded
group7 uksouth Succeeded
group8 westeurope Succeeded
group9 westeurope Succeeded
however, if I try to select just the Name property by doing
az group list | select -p name
Then i get about 2 screens full of empty lines, with nothing displayed. So the question is, what's wrong with the command above? And how should I fix it?
I tried the following experiments to dig into the exact types of objects being returned and get some results that I don't understand. I'm hoping this will make sense to someone with more Azure and powershell experience.
Here's the steps to reproduce the problem very easily, assuming you have an azure account.
start powershell, e.g. on mac terminal, type pwsh
log in to azure az login
type az group list -o table
observe that the list comes back and is formatted correctly.
type az group list | select -p name
observe a few screens full of blank lines. no text.
scratch your head and wonder whats just happened? (grin)
THE PLOT THICKENS
az group list on it's own returns a few screens full of this
[
... lots of these ...
{
"id": "/subscriptions/this-is-super-wierd-i-cant-select-name-prop/resourceGroups/spikes",
"location": "westeurope",
"managedBy": null,
"name": "spikes",
"properties": {
"provisioningState": "Succeeded"
},
"tags": {},
"type": null
}
]
however, (az group list).getType() returns
PS src> (az group list).getType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
and lastly, hopefully the last 2 pieces of the puzzle
PS src> (az group list)[0].getType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
so the return types from az group list appear to be an array of objects or maybe it's an array of object[], my powershell is scratchy here. So to double check, I query for the first 10 elements of that array by doing...(az group list)[0..10] and that returns bizarely 10 strings!. Ok, I know it's supposed to be 10 strings, only because it's a computer and if that's what it is, then, that's what it really is. I just dont understand why.
[
{
"id": "/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/somegroup",
"location": "westeurope",
"managedBy": null,
"name": "admin",
"properties": {
"provisioningState": "Succeeded"
},
"tags": {},
"type": null
So all of this, to cut a long story short, is I'm wanting to know, how do you select just one property from the result of an azure query? In my case, I simply want to display the names of all my resource groups.
This az group list | select -p name should work, but does not, and I'd like to know how to do it properly, and in the process find out why it didn't work, and we can all learn something about Azure and powershell in the process, and life can be great!
Love you all,
Alan
Let's work through this. When we specify -o table e.g.:
az group list -o table
We say to Azure PowerShell CLI take the JSON content you get, and format it into a nice table for us. Typically, we don't want to work with RAW JSON, and we don't want to work with formatted tables either. Working with string arrays in PowerShell are also not a nice thing to use. In PowerShell, we want to work with "nice" easy objects. So, let's look at the other ways to get our information. Let's take your example and simply save it to a variable that we can look at:
$GroupList = az group list
Then if we look as the type:
PS C:\> $GroupList.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
Indeed, we have an array of objects. They must be an array of our groups... right?... well no. It's not what you think. If we look at the size of the array and return the first few elements of the array we will see what's going on:
PS C:\> $GroupList.Count
125
PS C:\Temp> $GroupList[0..2]
[
{
"id": "/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/somegroup",
Well, that's not what we wanted. The array is far to large... and looking at the content reveals that what we actually have is an array of each line of the JSON text. This means that running:
az group list | select -p name
or:
$GroupList | select -p name
Is saying, loop through the array, and only output the "Name" property. Since the "Name" property does not exist on a string of text, it simply outputs a blank line. Since there are a few hundred lines of text, we get a few hundred lines of blanks.
So why does PowerShell take the input and break it into an array of strings separated by new lines? Isn't this kinda hard to use? Isn't this not a "great" way to handle a JSON formatted text? Why don't we just get one giant string? Isn't that easier to handle and parse? What's the one reason for this oddness?
Well with PowerShell, the need to support pipelines drives decisions on how we output objects:
"The primary purpose ... is to provide a way to ensure that the result of a pipeline execution is always an indexable collection."
Quote
This is why we get an array of objects outputted (See: #mklement0 answer here for more in depth discussion) to support pipeline operations. And if we look at how text files are read and written to, we can highlight exactly why we end up with this specific cough Programmer cough convenience cough... I mean weirdness.
To set things up, we can pipe the output directly to a text file:
az group list | Out-File -FilePath List.json
Woah, wait a second, why did that just work? (In situations like this, I like to say that PowerShell does Magic!), Don't we have to mess with looping through arrays, appending strings terminated with newlines to get one giant contiguous block of text that ends with an EOF, and exactly matches our desired text file?
A simplified reason behind what really happens? Well, out of programmer convenience, Out-File takes the array of strings, iterates through it, and does a simple File.WriteLine() for each string (not bad for a 3 line for loop!). Hence, we just generated a nice JSON formatted text file complete with newlines without breaking a sweat. Reading it back in:
PS C:\> $ListFromFile = Get-Content .\List.json
PS C:\> $ListFromFile.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
PS C:\> $ListFromFile.Count
125
Does the reverse. It takes the file, does a File.ReadLine(), appends the strings to an array, and returns it. That's why we end up with an object array that contains strings.
Now, what do we really want? Well we know from the start, we don't want to work with one giant string, and we especially don't want to work with strings in an object array, what we want to work with is a nice native PSCustomObject that we can access. That's what PowerShell works best with, that's what we work best with. So, we simply have to convert our (big air quotes) "text input", which we know is formatted as JSON, and convert it into an object:
$List = $GroupList | ConvertFrom-Json
And looking at the count and properties:
PS C:\> $List.Count
10
PS C:\> $List.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
PS C:\> $List[0].GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False PSCustomObject System.Object
We see the count now matches how many groups we have, and the types are no longer an array of strings, but actual objects. So... Now, we can start sorting and selecting:
PS C:\> $List | select -Property Name
Name
----
group0
group1
group2
group3
group4
group5
group6
group7
group8
group9
And we get the output that we really wanted.
wow, so much text for something as simple as:
az group list --query '[].name' -o tsv

powershell Get-ChildItem iis:\sites | Export_CliXml sites.xml doesn't result in same as string output

Short:
Get-ChildItem IIS:\Sites
Get-ChildItem IIS:\Sites | Get-CliXml sites.xml
returns one thing as string and another as xml. Why?
Longer:
When I run
Get-ChildItem IIS:\Sites
I get something in the line of
Name ID State Phys...
Default Web Site 1 Started C:\i...
MyTestSite 2 Started C:\i...
but when I pipe it to Export-CliXml like so:
Get-ChildItem IIS:\Sites | Get-CliXml sites.xml
I get nothing with "Default Web Site" or "MyTestSite" in it. => The string and xml don't have anything in common.
When I do the same with Get-Process
Get-Process | Export-CliXml processes.xml
I can find my processes in the output file. => What is in the string can be found in the xml.
Why does Get-Process output about the same as text and xml
while Get-ChildItems IIS:\Sites one text and something else as xml?
What is it I have misunderstood?
I guess a problem might be that I get an exception from Get-ChildItem iis:\sites but output is still generated. The xml output seems ok too.
Update:
When I do
Get-ChildItem IIS:\Sites | select Name,ID,State,PhysicalPath | Get-CliXml sites.xml
I get the values I am looking for.
When I add Bindings
Get-ChildItem IIS:\Sites | select Name,ID,State,PhysicalPath,Bindings | Get-CliXml sites.xml
only 2 sites are iterated and I get an error message. The xml is fine anyway. (some well constructed try-catch in the code i believe)
Can someone confirm or deny that
get-childitem iis:\sites
gives back an object with lots of objects (not strings and integers)
and when this is piped to
export-clixml
the code will do a ToString on every property and return type names for them.
If the above is the case (which it probably is) the solution is to
Get-ChildItem IIS:\Sites | select Name,ID,State,PhysicalPath | Get-CliXml sites.xml
but not for complex properties like Binding.

Resources