I am trying to collect an accurate picture of Windows Updates, specifically KB installations, on a number of different machines. I've tried a number of different pieces of code that I've found scattered about, but I still cannot seem to create an accurate picture of what is installed. By accurate, I mean that whatever I gather seems to be a subset of what is shown when I check the Windows Update History on the machine using the Windows UI! Can't seem to figure this out!
Here are a few things I've tried;
UpdateSession uSession = new UpdateSession();
IUpdateSearcher uSearcher = uSession.CreateUpdateSearcher();
uSearcher.Online = false;
ISearchResult sResult = uSearcher.Search("IsInstalled=1");
foreach (IUpdate update in sResult.Updates)
{
foreach (string kbaid in update.KBArticleIDs)
{
txtAllUpdates.AppendText(kbaid + Environment.NewLine);
}
}
I also tried adding code within this same routine to gather all of the updates within the Bundled Updates field, like so;
foreach (IUpdate update2 in update.BundledUpdates)
{
txtAllUpdates.AppendText("\t--> " + update2.Title + Environment.NewLine);
foreach (string kbaid2 in update2.BundledUpdates)
{
string kbNo = GetKBNo(update2.Title.ToLower());
txtAllUpdates.AppendText("\t\t" + kbNo);
}
}
I also tried looking at the Update History, but that provided me with yet another set of data - still not complete!
UpdateSession updateSession = new UpdateSession();
IUpdateSearcher updateSearcher = updateSession.CreateUpdateSearcher();
int count = updateSearcher.GetTotalHistoryCount();
MessageBox.Show("Total Count = " + count);
IUpdateHistoryEntryCollection history = updateSearcher.QueryHistory(0, count);
for (int i = 0; i < count; ++i)
{
txtAllUpdates.AppendText("\t\t\t" + history[i].Title);
}
I also checked into some code that leverages the registry, but from what I've read, that's not the right way to do things. At this point, I'm performing a number of different queries, searching entries for "KB" references and building a list and removing duplicates, but I'm still not getting the same list I see on the screen! Even if this did work, it can't possibly be the right way to go - I feel like I must be missing something.
Finally, I tried to just get information on when updates were last checked for and installed - even that doesn't match up with what is displayed. I did this with the following code;
var auc = new AutomaticUpdatesClass();
DateTime? lastInstallationSuccessDateUtc = null;
if (auc.Results.LastInstallationSuccessDate is DateTime)
lastInstallationSuccessDateUtc = new DateTime(((DateTime)auc.Results.LastInstallationSuccessDate).Ticks, DateTimeKind.Utc);
DateTime? lastSearchSuccessDateUtc = null;
if (auc.Results.LastSearchSuccessDate is DateTime)
lastSearchSuccessDateUtc = new DateTime(((DateTime)auc.Results.LastSearchSuccessDate).Ticks, DateTimeKind.Utc);
lblInstall.Text += lastInstallationSuccessDateUtc.ToString();
lblSearch.Text += lastSearchSuccessDateUtc.ToString();
Does anyone have some expertise in this area? Really want to get this done right!
Thanks for taking the time to read!
Respectfully,
Marshall
All the various ways to find installed software is incomplete, so I used a variety of ways in Get-KbInstalledUpdate, which I describe as a:
Replacement for Get-Hotfix, Get-Package, searching the registry and searching CIM for updates
Though I haven't tried this way, which is essentially:
$session = New-Object -ComObject "Microsoft.Update.Session"
$updatesearcher = $session.CreateUpdateSearcher()
$count = $updatesearcher.GetTotalHistoryCount()
$updates = $updatesearcher.QueryHistory(0, $count)
Related
I have a lot of VBA automation that interlinks an Outlook and Word solution; it is fine, but time is inexorable... so, I'm start to decorating and extending that old solution, wraping it with C#/VS2017.
Through a conventional Winform I can choose my patients, and from this action I do a lot of actions, including open the correct Outlook contact; that's the problem, because I can't get the correct Store; the patients.pst, depending on the machine, may be the 1st, 2nd, 3rd...
In VBA I do this:
WhichStoreNameToPointAt="patients"
Set myNamespace = myolApp.GetNamespace("MAPI")
For i = 1 To myNamespace.Stores.Count Step 1
If myNamespace.Stores.item(i).DisplayName = WhichStoreNameToPointAt Then
intOutlookItemStore = i
End if
End If
Set myFolderPatients = myNamespace.Stores.item(intOutlookItemStore).GetDefaultFolder(olFolderContacts)
And it always functions like a charm.
In C# I tried a lot of variations, and could not point to the correct store:
public void OpenPatientContact(string patientName)
{
Outlook.Store whichStore = null;
Outlook.NameSpace nameSpace = OlkApp.Session;
int i = 1;
foreach (Outlook.Folder folder in nameSpace.Folders)
{
bool p = false;
if (whichStoreNameToPointAt == folder.Name)
{
p = true;
whichStore = folder.Store;
//Correct Store selected; I can tell because of this watch:
//whichStore.displayname == whichStoreNameToPointAt
}
i++;
if (p)
break;
}
var contactItemsOlk = whichStore.Session.GetDefaultFolder
(Outlook.OlDefaultFolders.olFolderContacts).Items;
// The problem is below; always the first Store
Outlook.ContactItem contact = (Outlook.ContactItem)contactItemsOlk
.Find(string.Format("[FullName]='{0}'", patientName)); //[1];
if (contact != null)
{
contact.Display(true);
}
else
{
MessageBox.Show("The contact information was not found.");
}
}
Unfortunately, it keeps pointing ever to the same first Store, the one that has no patients...
If I change the Store order I can get past this and test other stuff, but of course it is not the right way.
Any other heads/eyes to see the light?
TIA
While seated writing the question, looking at a yellow rubber duck - and a lot of other stuff that belongs to my 1 yo daughter ;), I realized that whichStore.Session.GetDefaultFolder is a little strange in this context. I only changed this
var contactItemsOlk = whichStore.Session.GetDefaultFolder
(Outlook.OlDefaultFolders.olFolderContacts).Items;
To that:
var contactItemsOlk = whichStore.GetDefaultFolder
(Outlook.OlDefaultFolders.olFolderContacts).Items;
Voilá! Magic happens with C# too!
Session returns the default NameSpace object for the current session.
PS: yellow rubber duck; guys of The Pragmatic Programmer really knows some secrets and tricks ;)
Thanks Thomas and Hunt!
I have to record the coordinate-data (vector of x,y,z) of an eye-tracking System and save it, for later evaluation. The whole eye-tracking System is integrated inside a Head-mounted-Display and the software runs over Unity.
After some research, I figured out that saving the Data in a CSV file would probably the easiest way. This is what I got so far:
void update()
{
string filePath = #"C:\Data.csv";
string delimiter = ",";
Vector3 leftGazeDirection = smiInstance.smi_GetLeftGazeDirection();
Vector3 rightGazeDirection = smiInstance.smi_GetRightGazeDirection();
float[][] output = new float[][]{
new float[]{leftGazeDirection.x},
new float[]{leftGazeDirection.y},
new float[]{leftGazeDirection.z},
new float[]{rightGazeDirection.x},
new float[]{rightGazeDirection.y},
new float[]{rightGazeDirection.z} };
int length = output.GetLength(0);
StringBuilder sb = new StringBuilder();
for (int index = 0; index < length; index++)
sb.AppendLine(string.Join(delimiter, output[index]));
File.WriteAllText(#"C:\Data.csv", sb.ToString());
}
What this gives me out is a CSV file with the Vector of the latest Position of the Gazedirection. What I need would be a Record of all the Gazedirections that were made in one Session. Is it possible to get something like this?
Can I somehow modify my Code to achieve this or should I try something completely different?
Since I'm very newbie to unity and programming in general I just have a lack of vocabulary and don't know what to search for to solve my problem..
I would be very thankful if somebody could help me. :)
Welcome to StackOverflow. A good question, and well set out.
Presumably after you save this data away, you want to do something with it. I would suggest that your life is going to be a lot easier if you were to create a database to store your data. There are tons of tutorials on this sort of thing, and since you are already writing in C# it should not be too hard for you.
I would be creating a SQL Server database - either the Express version or Developer Version, both would be free for you.
I would steer away from trying Entity Framework or similar at this stage, I would just use the basic SQLClient to connect and write to your database.
Once you start using this then adding something like a Session column to separate one session from the next becomes easy, and all sorts of analysis you might want to do onthe data will also become much easier.
Hope this helps, and good luck with your project.
Yes. You can have data for one entire session. Look no further than File.AppendAllText. In this scenario I'm assuming that you have 6 values for two gaze pointers. In that case you don't need to write it down as multidimensional array as it is just wasting allocated memory.
Here we can proceed to save it as 6 values for each iteration of your loop.
string filePath = #"C:\Data.csv";
string delimiter = ",";
void Start()
{
if(File.Exists(filePath))
File.Delete(filePath);
}
void Update
{
Vector3 leftGazeDirection = smiInstance.smi_GetLeftGazeDirection();
Vector3 rightGazeDirection = smiInstance.smi_GetRightGazeDirection();
float[] output = new float[]{
leftGazeDirection.x,
leftGazeDirection.y,
leftGazeDirection.z,
rightGazeDirection.x,
rightGazeDirection.y,
rightGazeDirection.z };
int length = output.Length;
StringBuilder sb = new StringBuilder();
for (int index = 0; index < length; index++)
sb.AppendLine(output[index],delimiter));
if(!File.Exists(filePath))
File.WriteAllText(filePath, sb.ToString());
else
File.AppendAllText(filePath, sb.ToString());
}
AppendAllText will keep on appending file till the end of execution. Note that this solution has downside that is at the start we will delete the file for each session so you will need to manually keep track of each session.
So if you want to keep a bunch of files related to each session and not to overrride the same file we can include the date and time stamp while creating each file. So instead of deleting old file for each new session we are creating file for each session and writing in it. Only start method will need to change to handle datetime stamp for file name appending. Rest of the Update loop will be same.
string filePath = #"C:\Data";
string delimiter = ",";
void Start()
{
filePath = filePath + DateTime.Now.ToString("yyyy-mm-dd-hh-mm-ss") + ".csv";
}
I've been trying to figure out how to do this but I'm always met with a bump on the road. What I'm trying to do is to get the reporting people under my manager's direct reports list; so for example, "Alex" is a direct report under my manager, however, when you go into his organization you see that he also has direct reports that report directly to him - I am trying to get "those" reports not only from his side but from anyone else in the list that has direct reports as well. What is needed for me to effectively execute that idea? Many thanks!
This is my code to only get Direct Reports under my manager tree:
public void GetManagerDirectReports()
{
Application App = new Application();
AddressEntry currentUser = App.Session.CurrentUser.AddressEntry;
if (currentUser.Type == "EX")
{
ExchangeUser manager = currentUser.GetExchangeUser().GetExchangeUserManager();
if (manager != null)
{
AddressEntries addrEntries = manager.GetDirectReports();
if (addrEntries != null)
{
foreach (AddressEntry addrEntry in addrEntries)
{
ExchangeUser exchUser = addrEntry.GetExchangeUser();
StringBuilder sb = new StringBuilder();
sb.AppendLine("Name: "
+ exchUser.Name);
sb.AppendLine("Title: "
+ exchUser.JobTitle);
sb.AppendLine("Department: "
+ exchUser.Department);
sb.AppendLine("Email: "
+ exchUser.PrimarySmtpAddress);
Debug.WriteLine(sb.ToString());
Console.WriteLine(sb.ToString());
Console.ReadLine();
}
}
}
}
}
I opted to go ahead and use LDAP instead of Microsoft's EWS because I saw it uses _ComObject and I don't believe that will work with what I need it to work for. Essentially, I created a master load class and then a sub-class to handle LDAP syntax which would give me the emails of all managers who have direct reports. Something I found useful while doing my research is this filter string which came in quite handy in my time of need (where "cn" is the manager's name):
searcher = new DirectorySearcher
{
Filter = "(&(objectClass=user)(objectCategory=person)(manager=" + cn + ",OU=Unit,OU=People,DC=my,DC=domain,DC=com))"
};
searcher.PropertiesToLoad.Add("DirectReports");
searcher.PropertiesToLoad.Add("mail");
Hope this can serve of some use to coming questions related to this in the future.
I can get connected to HP ALM via c# OTA no problem. It's what is supposed to happen next that isn't clear. I have looked all over HPs documentation for OTA but not much there in regards to updating a test run.
I can make a connection to ALM no problem. I then create a TestSetFactory and RunFactory. I don't know what to do from here. I'm trying to add a run for a particular test set in ALM. I want to add a run and set it to either Pass or Fail and add a comment.
TestSetFactory tsFactory = (TestSetFactory)qcConn.TestSetFactory;
RunFactory runFactory = (RunFactory)qcConn.RunFactory();
Does anyone know how to do this? Is there a previous post that I can't find? Please give me the link and I will happily go there.
If anyone else has figured this out can you please post your code?
Okay, after much trial and error I figured it out. I'm sure there are easier ways to do it but I haven't figured them out yet.
To create a run and update it's status and that of it's steps here's what you need to run:
//This assumes you are already connected to ALM and your project.
string testFolder = #"Root\whatever your folder name is";
TestSetFactory tstFactory = (TestSetFactory)qcConn.TestSetFactory;
TestSetTreeManager tsTreeMgr = (TestSetTreeManager)qcConn.TestSetTreeManager;
TestSetFolder tsFolder = (TestSetFolder)tsTreeMgr.get_NodeByPath(testFolder);
List tsList = tsFolder.FindTestSets("MyTestSet", false, null);
foreach (TestSet ts in tsList)
{
TestSetFolder tstFolder = (TestSetFolder)ts.TestSetFolder;
TSTestFactory tsTestFactory = (TSTestFactory)ts.TSTestFactory;
List mylist = tsTestFactory.NewList("");
foreach (TSTest tsTest in mylist)
{
RunFactory runFactory = (RunFactory)tsTest.RunFactory;
Run run = (Run)runFactory.AddItem("Name of your run here");
run.CopyDesignSteps();
run.Status = "Passed";
run.Post();
StepFactory stepFactory = (StepFactory)run.StepFactory;
dynamic stepList = stepFactory.NewList("");
var rstepList = (TDAPIOLELib.List)stepList;
foreach (dynamic rstep in rstepList)
{
rstep.Status = "Passed";
rstep.Post();
}
}
}
As the question says, I have an InfoPath form running on SP2010 using a c# workflow upon submission. If the form is rejected during workflow, then I need to reset it. I have everything under control, EXCEPT how to reset digital signatures to null, nill, nada, nothing, non-extant! Any ideas? I'm looking at Google now, but at current, I'm not even sure of an om for digital signatures?
Wow, i notice this question suddenly gaining alot of pop with bounty almost gone. Just putting it out there, I did not intend to not bounty someone, but i needed the answer earlier this week (2nd week Nov 2012) and thus i searched and played and teetered with code as much as possible till i ended up finding my own answer before anyone else answered me. However, for future reference, if someone gives a better answer, i'll gladly come back and rep them. Thank you all for the support and I really hope my answer is as useful to another as it was to me.
NOW Bloggered && Gisted May no one ever again have to search as hard as I did for this answer, :P
¡¡¡ I F O U N D M Y F R I G G I N ' A N S W E R ! ! !
¡¡¡ And it works from the workflow !!!
Through much trial and tribulation I was finally able to come up with a solution. It involves a few steps. One, elevate security! Otherwise, non-admin users will cause the workflow to error. Seems like it should work this way, but ... Secondly, get the right schema! It took me a while to find mine, i forgot the exact steps, but, it's not hard to find. UPDATED: Can be found as an attribute of xmlDoc.Document, see updated code Step through (debug) your workflow, without the namespace/schema and highlight your document when it gets to it. One of the properties is an url that is the schema link. Anyway, you wanna see the solution!? Do ya? Look down!
SPSecurity.RunWithElevatedPrivileges(delegate()
{
SPFile formFile = workflowProperties.Item.File;
MemoryStream ms = new MemoryStream(formFile.OpenBinary());
XmlTextReader rdr = new XmlTextReader(ms);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(rdr);
rdr.Close();
ms.Close();
XmlNamespaceManager nsm = new XmlNamespaceManager(xmlDoc.NameTable);
String schemaUri = xmlDoc.DocumentElement.GetAttributeNode("xmlns:my") != null ? xmlDoc.DocumentElement.GetAttributeNode("xmlns:my").Value : "http://schemas.microsoft.com/office/infopath/2003/myXSD/2012-09-04T20:19:31";
nsm.AddNamespace("my", schemaUri);
XmlNode nodeSignatureCollection = xmlDoc.DocumentElement.SelectSingleNode("my:signatures1", nsm);
if (nodeSignatureCollection != null)
{
if (nodeSignatureCollection.HasChildNodes)
{
foreach (XmlNode nodeSignature in nodeSignatureCollection.ChildNodes)
{
// HERE IT IS!!!
if (nodeSignature.HasChildNodes && !nodeSignature.IsReadOnly) nodeSignature.RemoveAll();
}
}
}
byte[] xmlData = System.Text.Encoding.UTF8.GetBytes(xmlDoc.OuterXml);
formFile.SaveBinary(xmlData);
formFile.Update();
});
Keep in mind, this setup is for going through multiple signatures. Although I doubt anything would change if there was only one signature.
Any suggestions on making this sweeter and smaller are accepted, however, I must request an explanation. Honestly, I barely understand what is going on here!
The following answer only HALF works. It is left here for instructional purpose. (Full working answer can be found here.) It works for admin users, but nothing less. It also only works from the InfoPath form behind code. NOT from the workflow.
Adding elevated privlage seems to have 0 effect
I'm leaving this answer up here along with my other so that someone may learn from both examples or possibly even instruct others (including myself) via comments and what not on why one way may be better than the other. At this point, I really don't care to explain anymore as I really don't care to see any of this code ever again! LoL!
public void FormEvents_Loading(object sender, LoadingEventArgs e)
{
string[] actionFields = new string[] { "/my:myFields/my:.../my:...", "/my:myFields/my:.../my:...", etc... };
for (int i = 0; i < actionFields.Length; i++)
{
String field = actionFields[i];
XPathNavigator node = this.MainDataSource.CreateNavigator().SelectSingleNode(field, this.NamespaceManager);
if (node.Value.ToLower() == "reject")
{
XPathNavigator sigNode = this.MainDataSource.CreateNavigator();
if (this.Signed) //then unsign it
{
for (int ii = 2; ii <= 13; ii++)
{
try
{
XPathNavigator xSignedSection = sigNode.SelectSingleNode(String.Format("my:myFields/my:signatures1/my:signatures{0}", ii), this.NamespaceManager);
if (xSignedSection.HasChildren)
{
xSignedSection.MoveToChild(XPathNodeType.Element); xSignedSection.DeleteSelf();
};
}
catch (Exception ex) { };
};
};
};
};
}